﻿// Date: 15.07.11

// Version 2.0 from 24.07.11
//
// Dependencies:
//  * ### 24.07.11 ###
//  - Deferred Renderer from Roy Triesscheijn 
//    http://roy-t.nl/index.php/2010/12/28/deferred-rendering-in-xna4-0-source-code/
//  * ### 27.07.11 ### 
//  - GoblinXNA DirectShow- and ALVAR Marker Tracking implementation 
//  * ### 29.07.11 ###
//  - Mercury Particle Engine 4.0 for 3D
//  * ### 15.09.11 ###
//  - Spot Light Implementation from "Deferred Rendering for XNA 4" by Celal Cansin Kayi
//  * ### 21.09.11 ###
//  - Wireframe implementation without z-fighting from Catalin's XNA blog
//  * ### 01.10.11 ###
//  - Kinect integration via Microsoft SDK
//  * ### 22.10.11 ###
//  - Integration of a debug grid and world axis
//  * ### 05.11.11 ###
//  - Integration of the BEPUphysics debug drawer
//  * ### 14.12.11 ###
//  - Integration of the "ReducedRGB" kinect mode
//  * ### 21.12.11 ###
//  - Integration of the Kinect speech recognition


// Revision 48



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Xml;
using BEPUphysics;
using BEPUphysics.CollisionShapes;
using BEPUphysics.CollisionShapes.ConvexShapes;
using BEPUphysics.Entities;
using BEPUphysics.MathExtensions;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using ProjectMercury;
using ProjectMercury.Renderers;
using NOVA.Physics;
using NOVA.Scenery;
using NOVA.Scenery.ComplexObjects;
using NOVA.Sound;
using NOVA.Components.MarkerTracking.iWear;
using NOVA.Utilities;
using Model = Microsoft.Xna.Framework.Graphics.Model;
using NOVA.Components.MarkerTracking.Capture;
using NOVA.Components.MarkerTracking.Vision.Marker;
using NOVA.UI;
using NOVA.Components.Move;
using NOVA.Components.Kinect;
using NOVA.Scenery;
using NOVA.Components.MarkerTracking.Capture;
using NOVA.Graphics;
using BEPUphysicsDrawer.Models;
using BEPUphysicsDrawer.Lines;
using Microsoft.Speech.Recognition;
using Microsoft.Speech.AudioFormat;
using BEPUphysics.CollisionTests;
using BEPUphysics.NarrowPhaseSystems.Pairs;
using BEPUphysics.Collidables;
using BEPUphysics.Collidables.MobileCollidables;

namespace NOVA.Scenery
{
    public enum RenderType
    {
        SimpleRenderer = 0,
        ForwardRenderer,
        DeferredRenderer
    }

    public class SceneChangedEventArgs : EventArgs
    {
        private ITransformable obj;

        public SceneChangedEventArgs(ITransformable obj)
        {
            this.obj = obj;
        }

        /// <summary>
        /// Gets or sets the scene object which is changed
        /// </summary>
        public ITransformable Object
        {
            get { return this.obj; }
            set { this.obj = value; }
        }
    }
        
    /// <summary>
    /// Main class of NOVA, which implements the processing and rendering of all objects 
    /// added to this scene.
    /// </summary>
    public class Scene //: DrawableGameComponent//: GoblinXNA.SceneGraph.Scene
    {
        #region Members
                
        Game m_game;
        GraphicsDeviceManager m_graphics;
        public bool m_bSelfClear;

        DebugGrid m_grid;
        bool m_bShowGrid;

        internal Dictionary<Entity, SceneObject> CollidersList;

        bool m_bIsDisposed = false;

        #region Speech Recognition
        private bool bRunningSpeechRecognition;
        private SpeechRecognitionEngine sre;
        #endregion

        #region Marker Tracking
        IntPtr m_pBufferedVideoPtr;
        IMarkerTracker m_markerTracker;
        IVideoCapture m_videoCaptureDevice;
        Thread m_markerTrackingThread;
        bool m_bMarkerTrackingInitialized;
        ulong m_lTrackerUpdateCount;
        ulong m_lFrameUpdateCount;
        bool m_bFreezeVideo;
        bool m_bShowCameraImage;
        int[] m_iBufferedVideoImage;
        float m_fPrevTrackerTime;
        Texture2D m_VideoTexture;
        bool m_bRenderingVideoTexture;
        bool m_bCopyingVideoImage;
        SpriteBatch m_spriteBatch;
        Color m_VideoBackgroundColor;
        Color m_BackgroundColor;        
        int m_iPrevPointerSize;
        bool m_bReadyToUpdateTracker;
        bool m_bSpriteActive;

        // These variables are used to avoid updating the tracker while changing the video overlay
        // ID or tracker ID, or visa versa
        bool m_bWaitForVideoIDChange;
        bool m_bWaitForTrackerUpdate;

        Matrix tmp1, tmp2, tmp3;
        Vector3 markerTranslation;
        Quaternion markerRotation;
        Vector3 markerScale;
        #endregion

        List<SceneObject> m_sceneObjectsList;
        List<LightObject> m_sceneLightsList;
        List<CameraObject> m_sceneCamerasList;
        List<Controller> m_sceneControllersList;
        List<ARMarkerController> m_sceneMarkerControllersList;
        List<ParticleObject> m_sceneParticleList;
        List<SoundObject> m_sceneSoundsList;
        List<Text3D> m_sceneText3D;
        List<ISpaceObject> m_scenePhysicsList;

        List<SceneObject> m_groupTransparency = new List<SceneObject>();
        List<SceneObject> m_groupOcculuder = new List<SceneObject>();

        //AudioManager m_audioManager;
        AudioListener m_audioListener;
        AudioEmitter m_audioEmitter;
        Vector3 m_prevAudioListenerPos = Vector3.Zero;

        BoundingBox m_deathZone;

        //SSAO m_ssao;

        //RenderTarget2D m_ssaoRT;

        float m_shatterTime;

        WireframeRenderer m_wireframeRenderer;
        bool m_bRenderWireframes;

        bool m_bRenderCollisionMeshes;
        Color m_colorCollisionMesh;
        BasicEffect effectCollision;

        #region Vuzix
        bool m_bStereoMode;
        iWearTracker iTracker;
        Viewport leftViewport;
        Viewport rightViewport;
        bool m_bRenderLeftEye;
        #endregion

        #region Particles
        private AbstractRenderer m_particleRenderer;
        #endregion

        #region Move
        PSMoveCalibration m_psMove;
        bool m_bPSMoveEnabled;
        #endregion

        #region Kinect
        Kinect m_kinect;
        bool m_bKinectEnabled;
        #endregion

        Texture2D m_BackgroundTexture;

        BasicEffect effect;
        Effect m_effectDR;

        UnifiedShader m_unifiedShader;

        CameraObject m_currentCamera;

        Space m_physicsEngine;
        bool m_bPausePhysics;
        CollisionMeshRenderer m_collisionMeshRenderer;
        BoundingBoxDrawer m_boundingboxRenderer;
        BasicEffect LineDrawer;
        LineDrawer m_constraintsRenderer;

        UIRenderer m_uiRenderer;

        long _frameCounter = 0;
        TimeSpan _elapsedTime = TimeSpan.Zero;
        long _frameRate = 0;

        #region Rendering
        private QuadRenderComponent quadRenderer;

        private RenderTarget2D colorRT; //color and specular intensity
        private RenderTarget2D normalRT; //normals + specular power
        private RenderTarget2D depthRT; //depth
        private RenderTarget2D lightRT; //lighting

        private Effect clearBufferEffect;
        private Effect directionalLightEffect;
        private Effect pointLightEffect;
        private Effect spotLightEffect;
        private Model sphereModel; //point light volume
        private Model coneModel;

        private Effect finalCombineEffect;

        private Vector2 halfPixel;

        //private bool m_bSSAO;

        Model[] models;

        SpriteFont m_font;

        RenderTargetBinding[] targets;

        RenderType m_renderType;
        private bool showConstraints;
        private string name;
        private bool showBoundingBoxes;
        private bool enableLighting;
        #endregion

        #endregion

        #region Properties

        public Color VideoColorBackground
        {
            get { return m_VideoBackgroundColor; }
            set { m_VideoBackgroundColor = value; }
        }

        /// <summary>
        /// Returns the speech recognition engine instance.
        /// </summary>
        public SpeechRecognitionEngine SpeechRecognitionEngine { get { return sre; } }

        /// <summary>
        /// Gets the current recognizer info.
        /// </summary>
        public RecognizerInfo RecognizerInfo { get { return GetKinectRecognizer(); } }

        /// <summary>
        /// Returns a class that contains all Vuzix data like the sensor data for roll, pitch and yaw.
        /// </summary>
        public iWearTracker VuzixData
        {
            get { return iTracker; }
        }

        /// <summary>
        /// Gets or sets the collision mesh color.
        /// </summary>
        public Color CollisionMeshColor
        {
            get { return m_colorCollisionMesh; }
            set { m_colorCollisionMesh = value; }
        }

        /// <summary>
        /// Gets or sets whether to display a debug grid at the y=0 plane and the world axes
        /// </summary>
        public bool ShowGrid
        {
            get { return m_bShowGrid; }
            set { m_bShowGrid = value; }
        }

        /// <summary>
        /// Gets or sets whether to display the Frames-Per-Second count on the screen.
        /// </summary>
        public bool ShowFPS
        {
            get { return Core.ShowFPS; }
            set { Core.ShowFPS = value; }
        }

        /// <summary>
        /// Gets or sets whether to display the current camera position on the screen.
        /// </summary>
        public bool ShowCameraPosition
        {
            get { return Core.ShowCameraPosition; }
            set { Core.ShowCameraPosition = value; }
        }

        /// <summary>
        /// Gets or sets whether to display any notification messages on the screen.
        /// </summary>
        public static bool ShowNotifications
        {
            get { return Core.ShowNotifications; }
            set { Core.ShowNotifications = value; }
        }

        /// <summary>
        /// Gets or sets whether to display the triangle count of all of the rendered 
        /// models in the scene.
        /// </summary>
        public static bool ShowTriangleCount
        {
            get { return Core.ShowTriangleCount; }
            set { Core.ShowTriangleCount = value; }
        }

        /// <summary>
        /// Unvisible bounding box of the scene, where the objects can live. 
        /// If they leave this area, then they will be removed automatically.
        /// </summary>
        public BoundingBox DeathZone
        {
            get { return m_deathZone; }
            set { m_deathZone = value; }
        }

        /// <summary>
        /// Provides access to the Kinect interface.
        /// </summary>
        public Kinect Kinect
        {
            get { return m_kinect; }
        }

        /// <summary>
        /// Provides access to the PS Move Controller.
        /// </summary>
        public PSMoveCalibration MoveController
        {
            get { return m_psMove; }
        }

        /// <summary>
        /// If enabled, the image of the currently active camera is 
        /// shown in the background of the scene.
        /// </summary>
        public bool ShowCameraImage
        {
            get { return m_bShowCameraImage; }
            set { m_bShowCameraImage = value; }
        }

        /// <summary>
        /// If enabled, the constraints and joints are visualized using debug lines.
        /// </summary>
        public bool ShowConstraints 
        {
            get { return this.showConstraints; }
            set { this.showConstraints = value; }
        }

        /// <summary>
        /// If enabled, the collision meshes of the model objects are rendered.
        /// The collision meshes of the primitive models are not rendered, because
        /// the use an exact collision mesh.
        /// </summary>
        public bool ShowCollisionMeshes
        {
            get { return m_bRenderCollisionMeshes; }
            set { m_bRenderCollisionMeshes = value; }
        }

        /// <summary>
        /// If enabled, the wireframes of all scene objects is rendered.
        /// </summary>
        public bool ShowWireframe
        {
            get { return m_bRenderWireframes; }
            set { m_bRenderWireframes = value; }
        }


        //public bool EnableSSAO
        //{
        //    get { return m_bSSAO; }
        //    set { m_bSSAO = value; }
        //}

        /// <summary>
        /// Gets or sets the name of the scene.
        /// </summary>
        public string Name 
        {
            get { return this.name; }
            set { this.name = value; }
        }

        /// <summary>
        /// This can be used to pause the physics engine.
        /// </summary>
        public bool PausePhysics
        {
            get { return m_bPausePhysics; }
            set { m_bPausePhysics = value; }
        }

        public CollisionMeshRenderer CollisionMeshDrawer
        {
            get { return this.m_collisionMeshRenderer; }
        }

        /// <summary>
        /// Gets or sets the scene background texture.
        /// </summary>
        public Texture2D BackgroundTexture
        {
            get { return m_BackgroundTexture; }
            set { m_BackgroundTexture = value; }
        }

        /// <summary>
        /// Gets or sets the scene background color.
        /// </summary>
        public Color BackgroundColor
        {
            get { return m_BackgroundColor; }
            set { m_BackgroundColor = value; }
        }

        /// <summary>
        /// Gets or sets the marker tracking system.
        /// </summary>
        public IMarkerTracker MarkerTracker
        {
            get { return m_markerTracker; }
            set
            {
                if (value == null)
                    return;

                if (!value.Initialized)
                    ExceptionManager.Add(new Exception("You have to initialize the tracker before you assign " +
                        "to Scene.MarkerTracker"));

                m_markerTracker = value;

                if (m_currentCamera == null)
                {
                    CameraObject markerCamera = new CameraObject(Vector3.Backward, Vector3.Zero);

                    markerCamera.ViewMatrix = Matrix.CreateLookAt(new Vector3(0, 0, 0), new Vector3(0, 0, -1),
                        new Vector3(0, 1, 0));

                    m_currentCamera.ProjectionMatrix = m_markerTracker.CameraProjection;
                }
                else
                {
                    m_currentCamera.ProjectionMatrix = m_markerTracker.CameraProjection;
                }
            }
        }

        /// <summary>
        /// Gets the instance of the game class.
        /// </summary>
        public Game Game { get { return m_game; } }

        /// <summary>
        /// This can be used to access the scene physics engine.
        /// </summary>
        public Space Physics { get { return m_physicsEngine; } }

        /// <summary>
        /// If enabled, the bounding boxes of the scene objects are rendered.
        /// </summary>
        public bool ShowBoundingBoxes 
        {
            get { return this.showBoundingBoxes; }
            set { this.showBoundingBoxes = value; }
        }

        /// <summary>
        /// Gets a list of all scene objects.
        /// </summary>
        public List<SceneObject> SceneObjects
        {
            get { return m_sceneObjectsList; }
        }

        /// <summary>
        /// Gets a list of all scene lights.
        /// </summary>
        public List<LightObject> SceneLights
        {
            get { return m_sceneLightsList; }
        }

        /// <summary>
        /// Gets a list of all scene cameras.
        /// </summary>
        public List<CameraObject> SceneCameras
        {
            get { return m_sceneCamerasList; }
        }

        /// <summary>
        /// Gets a list of all physics objects in the scene
        /// </summary>
        public List<ISpaceObject> ScenePhysics
        {
            get { return m_scenePhysicsList; }
        }

        /// <summary>
        /// Gets a list of all particles of the scene
        /// </summary>
        public List<ParticleObject> SceneParticles
        {
            get { return this.m_sceneParticleList; }
        }

        /// <summary>
        /// If enabled, the scene lighting is used.
        /// </summary>
        public bool EnableLighting 
        {
            get { return this.enableLighting; }
            set { this.enableLighting = value; }
        }

        /// <summary>
        /// Gets or sets the currently active scene camera.
        /// </summary>
        public CameraObject Camera
        {
            get { return m_currentCamera; }
            set 
            {
                // TODO
                //if (!m_sceneCamerasList.Contains(value))
                //    m_sceneCamerasList.Add(value);

                m_currentCamera = value;
            }
        }

        /// <summary>
        /// Gets or sets the current scene render type.
        /// </summary>
        public RenderType RenderType
        {
            get { return m_renderType; }
            set { m_renderType = value; }
        }

        #endregion

        #region Events

        public event EventHandler<SceneChangedEventArgs> ObjectAdded;
        public event EventHandler<SceneChangedEventArgs> ObjectRemoved;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new scene, which can be used for 3D world.
        /// </summary>
        /// <param name="game">The current game, which runs NOVA.</param>
        /// <param name="graphics">The current graphics device manager of the game.</param>
        public Scene(Game game, GraphicsDeviceManager graphics)
            //: base(game)
        {
            m_game = game;
            m_graphics = graphics;
            m_bSelfClear = true;
            //game.Components.Add(this);
            //this.DrawOrder = 0;
            
            //m_bSSAO = false;

            m_unifiedShader = new UnifiedShader();

            //m_audioManager = new AudioManager(m_game);
            m_audioListener = new AudioListener();
            m_audioEmitter = new AudioEmitter();

            m_spriteBatch = new SpriteBatch(game.GraphicsDevice);

            m_sceneObjectsList = new List<SceneObject>();
            m_sceneLightsList = new List<LightObject>();
            m_sceneCamerasList = new List<CameraObject>();
            m_sceneControllersList = new List<Controller>();
            m_sceneMarkerControllersList = new List<ARMarkerController>();
            m_sceneParticleList = new List<ParticleObject>();
            m_sceneSoundsList = new List<SoundObject>();
            m_sceneText3D = new List<Text3D>();
            m_scenePhysicsList = new List<ISpaceObject>();

            this.CollidersList = new Dictionary<Entity, SceneObject>();

            m_physicsEngine = new Space();

            Core.QueryAccelerator = m_physicsEngine.BroadPhase.QueryAccelerator;

            m_bPausePhysics = false;

            m_wireframeRenderer = new WireframeRenderer(Game.GraphicsDevice);
            m_bRenderWireframes = true;
            m_bRenderCollisionMeshes = true;
            effectCollision = new BasicEffect(Core.Device);

            m_bPSMoveEnabled = false;
            
            m_uiRenderer = new UIRenderer();
            
            m_lTrackerUpdateCount = 0;
            m_lFrameUpdateCount = 0;
            m_bFreezeVideo = false;
            m_bShowCameraImage = false;
            m_pBufferedVideoPtr = new IntPtr();
            
            m_BackgroundTexture = null;
            m_BackgroundColor = Color.CornflowerBlue;
            m_VideoBackgroundColor = Color.White;
            m_fPrevTrackerTime = 0;
            m_bWaitForVideoIDChange = false;
            m_bWaitForTrackerUpdate = false;

            m_iBufferedVideoImage = new int[]{0};
            m_pBufferedVideoPtr = new IntPtr();

            m_bReadyToUpdateTracker = false;


            ShowBoundingBoxes = false;
            ShowCollisionMeshes = false;
            ShowFPS = true;
            ShowTriangleCount = true;
            ShowWireframe = false;

            m_bKinectEnabled = false;

            effect = new BasicEffect(game.GraphicsDevice);

            //ConfigurationHelper.ApplyDefaultSettings(m_physicsEngine);

            EngineSettings.GraphicsDevice = game.GraphicsDevice;
            
            m_renderType = RenderType.SimpleRenderer;
            EnableLighting = true;

            m_bStereoMode = false;

            m_shatterTime = 0f;

            m_colorCollisionMesh = Color.Purple;

            //game.Components.Add(quadRenderer);

            m_grid = new DebugGrid(Core.Device);
            m_grid.ViewMatrix = Matrix.Identity;
            m_grid.ProjectionMatrix = Matrix.Identity;
            m_grid.WorldMatrix = Matrix.Identity;
            m_bShowGrid = false;

            // Reset the debug info
            Core.ShowFPS = false;
            Core.ShowTriangleCount = false;
            Core.ShowNotifications = false;
            Core.ShowCameraPosition = false;
            
            //LoadContent();
        }

        /// <summary>
        /// Initializes the scene. This is called by the screen manager for every gameplay screen. Do not call it yourself!
        /// </summary>
        public /*override*/ void Initialize()
        {
            //base.Initialize();

            quadRenderer = new QuadRenderComponent(m_game);
            //m_game.Components.Add(quadRenderer);

            //m_audioManager.Initialize();

            // Initialize the collision mesh renderer
            m_collisionMeshRenderer = new CollisionMeshRenderer(this.Game);
            m_collisionMeshRenderer.IsWireframe = true;
            

            // Initialize the constraint renderer
            m_constraintsRenderer = new LineDrawer(this.Game);
            //m_constraintRenderer.DisplayTypes.Add(typeof(GrabSpring), typeof(DisplayGrabSpring));
            //m_constraintRenderer.DisplayTypes.Add(typeof(MotorizedGrabSpring), typeof(DisplayMotorizedGrabSpring));
            
            // Intitialize the bounding box renderer
            m_boundingboxRenderer = new BoundingBoxDrawer(this.Game);

            #region Particle
            m_particleRenderer = new SpriteBatchRenderer
            {
                GraphicsDeviceService = m_graphics,
                Transformation = Matrix.CreateTranslation(m_game.GraphicsDevice.Viewport.Width / 2f, m_game.GraphicsDevice.Viewport.Height / 2f, 0f)
            };

            Effect effect = Core.RenderGBuffer;
            m_particleRenderer = new QuadRenderer/*2*/(10000)
            {
                GraphicsDeviceService = m_graphics,
            };
            #endregion
            
            m_particleRenderer.LoadContent(m_game.Content);
        }

        #endregion

        #region Update & Draw
        
        /// <summary>
        /// Processes all scene logic. All components are processed here.
        /// </summary>
        public /*override*/ void Update(GameTime gameTime)
        {
            if (m_bIsDisposed)
                return;

            //foreach (SceneObject obj in m_sceneObjectsList)
            //    obj.Update(gameTime);
                      
            
            #region Sound

            if (m_currentCamera != null)
            {
                m_audioListener.Position = m_currentCamera.Position;
                m_audioListener.Forward = m_currentCamera.CameraTransformation.Forward;
                m_audioListener.Up = m_currentCamera.CameraTransformation.Up;
                m_audioListener.Velocity = (m_currentCamera.Position - m_prevAudioListenerPos) / (float)gameTime.ElapsedGameTime.TotalSeconds;
                m_prevAudioListenerPos = m_currentCamera.Position;

                Matrix world = Matrix.Identity;

                foreach (SoundObject sound in m_sceneSoundsList)
                {
                    if (sound.State == SoundState.Stopped)
                    {
                        if (sound.IsLooped)
                        {
                            sound.Play();
                        }

                        sound.IsActive = false;
                    }
                    else
                    {
                        if (sound.IsActive)
                        {
                            world = Matrix.CreateScale(sound.Scale) * Matrix.CreateFromQuaternion(sound.Orientation) * Matrix.CreateTranslation(sound.Position);

                            m_audioEmitter.Position = sound.Position;
                            m_audioEmitter.Forward = world.Forward;
                            m_audioEmitter.Up = world.Up;
                            m_audioEmitter.Velocity = sound.Velocity;

                            sound.Instance.Apply3D(m_audioListener, m_audioEmitter);
                        }
                    }
                }
            }
            #endregion

            //m_physicsEngine.TimeStepSettings.TimeStepCountPerFrameMaximum = 1;
            //m_physicsEngine.TimeStepSettings.TimeStepDuration = 1f / 120f;
            //m_physicsEngine.Update();//(float)gameTime.ElapsedGameTime.TotalSeconds);
            //m_physicsEngine.Update((float)gameTime.ElapsedGameTime.TotalSeconds);
            //m_physicsEngine.Update();
            

            // Update the camera view frustum for object culling during the rendering
            //if(m_currentCamera != null)
            //    m_currentCamera.ViewFrustum = new BoundingFrustum(m_currentCamera.ViewMatrix * m_currentCamera.ProjectionMatrix);

            //// Check the current movement
            //foreach (SceneObject obj in m_sceneObjectsList)
            //{
            //    //if (obj.Grabber.IsGrabbing)
            //    //    Console.WriteLine(obj.m_grabber.GrabbedPosition.ToString() + " | " + obj.Position.ToString() + " | " + obj.Grabber.GoalPosition.ToString());

            //    obj.ValidateMovement();
            //}

            

            #region Controllers
            // Update the controllers and it's children
            foreach (Controller ctrl in m_sceneControllersList)
            {
                UpdateController(ctrl);
            }
            #endregion

            // Apply the user movement before the physics update
            foreach (SceneObject obj in m_sceneObjectsList)
            {
                if (obj.m_bPositionProcessed)
                {
                    obj.MovingPosition(obj.m_movePosition);
                    obj.m_bPositionProcessed = false;
                }

                if (obj.m_bOrientationProcessed)
                {
                    obj.RotatingTo(obj.m_rotateOrientation);
                    obj.m_bOrientationProcessed = false;
                }
            }

            #region Physics
            if (!m_bPausePhysics)
            {
                //m_physicsEngine.TimeStepSettings.TimeStepCountPerFrameMaximum = 1;
                //m_physicsEngine.TimeStepSettings.TimeStepDuration = 1f / 120f;
                m_physicsEngine.Update();
            }
            #endregion

            #region Particles
            foreach (ParticleObject particle in m_sceneParticleList)
            {
                particle.Update((float)gameTime.ElapsedGameTime.TotalSeconds, m_currentCamera.ViewFrustum);
            }
            #endregion

            #region PS Move

            if(m_bPSMoveEnabled)
                m_psMove.Update(gameTime);

            #endregion

            #region Chase camera
            foreach (CameraObject cam in m_sceneCamerasList)
            {
                if (cam.ChaseObject != null)
                {
                    cam.Position += (cam.ChaseObject.Position - cam.m_lastChaseObjectPosition);

                    cam.m_lastChaseObjectPosition = cam.ChaseObject.Position;
                }
            }
            #endregion

            if (ShowCollisionMeshes)
            {
                m_collisionMeshRenderer.Update();
            }

            if (ShowConstraints)
            {
                // Clear all old constraints of the renderer
                m_constraintsRenderer.Clear();

                // Add all current constraints of the physics simulation
                for (int i = 0; i < m_physicsEngine.Solver.SolverUpdateables.Count; i++)
                {
                    //Add the solver updateable and match up the activity setting.
                    LineDisplayObjectBase objectAdded = m_constraintsRenderer.Add(m_physicsEngine.Solver.SolverUpdateables[i]);
                    if (objectAdded != null)
                        objectAdded.IsDrawing = m_physicsEngine.Solver.SolverUpdateables[i].IsActive;
                }

                m_constraintsRenderer.Update();
            }
            
            //Modify 
            //m_ssao.Modify(Keyboard.GetState()); 
            
            // Bug-fix
            //if(m_bMarkerTrackingInitialized)
            //    UpdateTrackerAndImage();

            //base.Update(gameTime);
        }

        /// <summary>
        /// The scene is rendered here with stereoscopic view, if enabled.
        /// </summary>
        public void Draw(GameTime gameTime)
        {
            if (m_bIsDisposed)
                return;

            if (m_bSelfClear)
                if (m_renderType == RenderType.ForwardRenderer || m_renderType == RenderType.SimpleRenderer)
                    m_game.GraphicsDevice.Clear(m_BackgroundColor);

            m_shatterTime += (float)gameTime.ElapsedGameTime.TotalSeconds;

            if (m_currentCamera == null)
            {
                CameraObject camera = new CameraObject(Vector3.Zero, Vector3.Forward);

                m_currentCamera = camera;

            }
            else
                m_uiRenderer.CameraPosition = m_currentCamera.Position;

            //m_physicsEngine.Update();

            if(m_bMarkerTrackingInitialized)
                UpdateTrackerAndImage();

            // Update the camera view frustum for object culling during the rendering
            m_currentCamera.ViewFrustum = new BoundingFrustum(m_currentCamera.ViewMatrix * m_currentCamera.ProjectionMatrix);
            

            if (m_bStereoMode)
            {
                ///////////// First, render the scene for the left eye view /////////////////
                iTracker.UpdateBottomLine(m_game);

                // Begin GPU query for rendering the scene
                iTracker.BeginGPUQuery();

                // Render the scene for left eye. Note that since base.Draw(..) will update the
                // physics simulation and scene graph as well. 
                m_currentCamera.ViewMatrix = m_currentCamera.LeftView;
                m_currentCamera.ProjectionMatrix = m_currentCamera.LeftProjection;
                m_bRenderLeftEye = true;
                OnDraw(gameTime);                              

                // Wait for the GPU to finish rendering
                iTracker.EndGPUQuery();

                // Signal the iWear VR920 that the image for the left eye is ready
                iTracker.SynchronizeEye(iWearDllBridge.Eyes.LEFT_EYE);
                
                
                    ///////////// Then, render the scene for the right eye view /////////////////

                    // Begin GPU query for rendering the scene
                    iTracker.BeginGPUQuery();

                    // Render the scene for right eye. Note that we called scene.RenderScene(...) instead of
                    // base.Draw(...). This is because we do not want to update the scene graph or physics
                    // simulation since we want to keep both the left and right eye view in the same time
                    // frame. Also, RenderScene(...) is much more light-weighted compared to base.Draw(...).
                    // The parameter forces the scene to also render the UI in the right eye view. If this is
                    // set to false, then you would only see the UI displayed on the left eye view.
                    m_currentCamera.ViewMatrix = m_currentCamera.RightView;
                    m_currentCamera.ProjectionMatrix = m_currentCamera.RightProjection;
                    m_bRenderLeftEye = false;
                    OnDraw(gameTime);

                    // Wait for the GPU to finish rendering
                    iTracker.EndGPUQuery();

                    // Signal the iWear VR920 that the image for the right eye is ready
                    iTracker.SynchronizeEye(iWearDllBridge.Eyes.RIGHT_EYE);
                
            }
            else
            {
                OnDraw(gameTime);
            }
            
        }

        /// <summary>
        /// Renders one scene frame.
        /// </summary>
        /// <param name="gameTime"></param>
        public void OnDraw(GameTime gameTime)
        {            
            //// Check the current movement
            //foreach (SceneObject obj in m_sceneObjects)
            //{
            //    //if (obj.Grabber.IsGrabbing)
            //    //    Console.WriteLine(obj.m_grabber.GrabbedPosition.ToString() + " | " + obj.Position.ToString() + " | " + obj.Grabber.GoalPosition.ToString());

            //    obj.ValidateMovement();
            //}
                                    
            EngineSettings.ViewMatrix = m_currentCamera.ViewMatrix;
            EngineSettings.ProjectionMatrix = m_currentCamera.ProjectionMatrix;
            Core.ViewMatrix = m_currentCamera.ViewMatrix;
            Core.ProjectionMatrix = m_currentCamera.ProjectionMatrix;
            
            //targets = m_game.GraphicsDevice.GetRenderTargets();
            
            PrepareScene();

            #region Marker Tracking

            if (iTracker != null)
                iTracker.Update(gameTime, true);
            
            // Update the marker tracking
            if (m_bMarkerTrackingInitialized)
            {
                foreach (ARMarkerController marker in m_sceneMarkerControllersList)
                {
                    if (marker.MarkerFound)
                    {
                        foreach (ITransformable att in marker.Children)
                        {
                            if (att is SceneObject)
                            {
                                // --------------------------------------------------------------------------
                                // The rotation matrix returned by the marker tracking has to be around it's
                                // forward vector to represent the real rotation matrix.
                                // --------------------------------------------------------------------------

                                tmp1 = marker.WorldTransformation;
                                att.ControllerMatrix = marker.WorldTransformation;


                                // Decompose the marker transformation to adjust the rotation
                                tmp1.Decompose(out markerScale, out markerRotation, out markerTranslation);

                                // Create an adjustment rotation delta
                                Quaternion delta = Quaternion.CreateFromAxisAngle(tmp1.Forward, (float)Math.PI / 2);

                                // Calculate the new rotation by rotation the marker rotation
                                Quaternion newRotation = Quaternion.Multiply(delta, markerRotation);

                                // Move the object using the grabber
                                ((SceneObject)att).TransformTo(markerTranslation, newRotation);
                            }
                        }
                    }
                }
            }
            #endregion

            #region Move camera image
            if (m_bPSMoveEnabled && m_bShowCameraImage)
                m_BackgroundTexture = m_psMove.GetCameraImage();
            #endregion

            #region Kinect
            if (m_bKinectEnabled && m_bShowCameraImage)
            {
                // Set the specific background image
                switch (m_kinect.ShowCameraImage)
                {
                    case Kinect.KinectCameraImage.Depth: 
                        m_BackgroundTexture = m_kinect.TextureDepth; 
                        break;
                    case Kinect.KinectCameraImage.ReducedRGB:
                    case Kinect.KinectCameraImage.RGB: 
                        m_BackgroundTexture = m_kinect.TextureColor; 
                        break;
                }                
            }
            #endregion

            RenderTexture();

            //State.Device.SamplerStates[0] = SamplerState.LinearWrap;
            //State.Device.Textures[0] = null;

            

            if (m_renderType == RenderType.DeferredRenderer && EnableLighting)
            {
                // Reset all previous graphics settings
                m_game.GraphicsDevice.BlendState = BlendState.Opaque;
                m_game.GraphicsDevice.DepthStencilState = DepthStencilState.None;

                SetGBuffer();
                ClearGBuffer();

                m_game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                m_game.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
                m_game.GraphicsDevice.BlendState = BlendState.Opaque;                
            }
            
            
            // Draw the grid
            if (m_bShowGrid)
            {
                m_grid.ViewMatrix = m_currentCamera.ViewMatrix;
                m_grid.ProjectionMatrix = m_currentCamera.ProjectionMatrix;
                m_grid.Draw(gameTime);
            }

            RenderScene();

            //if (m_renderType == GoblinXNA_Derivatives.RenderType.DeferredRenderer)
            //{
            //    //SetGBuffer();
            //    //ClearGBuffer();

            //    //m_game.GraphicsDevice.DepthStencilState = DepthStencilState.None;
            //    m_game.GraphicsDevice.BlendState = BlendState.Additive;

            //    m_game.GraphicsDevice.SetRenderTarget(colorRT);
            //}

            //// Render particle effects
            //Matrix world = Matrix.Identity;
            //Matrix view = m_currentCamera.ViewMatrix;
            //Matrix projection = m_currentCamera.ProjectionMatrix;
            //Vector3 pos = m_currentCamera.Position;
            //if (m_sceneParticleEffectsList.Count != 0)
            //    foreach (ParticleEffect effect in m_sceneParticleEffectsList)
            //        m_particleRenderer.RenderEffect(effect, ref world, ref view, ref projection, ref pos);
                        
            m_lFrameUpdateCount++;

            //Matrix world = Matrix.CreateTranslation(Vector3.Zero);
            //foreach (Model model in models)
            //{
            //    foreach (ModelMesh mesh in model.Meshes)
            //    {
            //        foreach (Effect eff in mesh.Effects)
            //        {
            //            eff.Parameters["World"].SetValue(world);
            //            eff.Parameters["View"].SetValue(m_currentCamera.ViewMatrix);
            //            eff.Parameters["Projection"].SetValue(m_currentCamera.ProjectionMatrix);
            //        }
            //        mesh.Draw();
            //    }

            //    world += Matrix.CreateTranslation(Vector3.Right * 15);
            //}

            if (m_renderType == RenderType.DeferredRenderer && EnableLighting)
            {
                ResolveGBuffer();

                DrawLights(gameTime);
                
                //// Draw non blurred ssao 
                //if (m_bSSAO)
                //{
                //    m_ssao.Draw(m_game.GraphicsDevice, new RenderTargetBinding[] { colorRT, normalRT, depthRT, lightRT }, m_ssaoRT, Camera, null);

                //    m_ssao.Debug(m_spriteBatch, m_font, new RenderTargetBinding[] { colorRT, normalRT, depthRT, lightRT });
                //}
            }


            NOVA.Utilities.DebugShapeRenderer.Draw((float)gameTime.ElapsedGameTime.TotalMilliseconds, m_currentCamera.ViewMatrix, m_currentCamera.ProjectionMatrix);



            #region Particles

            BlendState oldState = Core.Device.BlendState;
            Core.Device.BlendState = BlendState.AlphaBlend;

            // Render particle effects
            Matrix world = Matrix.Identity;
            Matrix view = m_currentCamera.ViewMatrix;
            Matrix projection = m_currentCamera.ProjectionMatrix;

            Vector3 pos = m_currentCamera.Position;

            if (m_sceneParticleList.Count != 0)
                foreach (ParticleObject effect in m_sceneParticleList)
                    m_particleRenderer.RenderEffect(effect.Effect, ref world, ref view, ref projection, ref pos);

            Core.Device.BlendState = oldState;

            #endregion

            #region 3D Text
            if (m_sceneText3D.Count > 0)
            {
                // Render 3D texts with special graphics modes for correct rendering
                RasterizerState oldRasterizerState = Core.Device.RasterizerState;
                BlendState oldBlendState = Core.Device.BlendState;

                // Disable the cull mode and enable the alpha blending
                Core.Device.RasterizerState = new RasterizerState() { CullMode = CullMode.None };
                Core.Device.BlendState = BlendState.AlphaBlend;

                List<Text3D> removingList = new List<Text3D>();

                foreach (Text3D txt in m_sceneText3D)
                {
                    txt.Draw(gameTime);

                    // If the text has expired, add it to the remove list
                    if (txt.Expired && !txt.NoRemoveWhenExpired)
                        removingList.Add(txt);
                }

                // Process the removing list and remove all text from the main list
                foreach (Text3D txt in removingList)
                    m_sceneText3D.Remove(txt);

                // Reset the graphics settings
                Core.Device.RasterizerState = oldRasterizerState;
                Core.Device.BlendState = oldBlendState;
            }
            #endregion

            #region Collision Mesh

            if (ShowCollisionMeshes)
            {
                RasterizerState oldRasterizer = Core.Device.RasterizerState;

                if (m_colorCollisionMesh != m_collisionMeshRenderer.Color)
                    m_collisionMeshRenderer.SetColor(m_colorCollisionMesh);

                // Render the collision meshes as wireframes with custom rasterizer
                m_collisionMeshRenderer.Draw(m_currentCamera.ViewMatrix, m_currentCamera.ProjectionMatrix);


                // Restore the old rasterize
                Core.Device.RasterizerState = oldRasterizer;
            }

            #endregion

            LineDrawer.LightingEnabled = false;
            LineDrawer.VertexColorEnabled = true;
            LineDrawer.World = Matrix.Identity;
            LineDrawer.View = m_currentCamera.ViewMatrix;
            LineDrawer.Projection = m_currentCamera.ProjectionMatrix;

            #region Bounding Box

            if (ShowBoundingBoxes)
                m_boundingboxRenderer.Draw(LineDrawer, m_physicsEngine);

            #endregion

            #region Contraint Renderer

            if (ShowConstraints)
            {
                m_constraintsRenderer.Draw(m_currentCamera.ViewMatrix, m_currentCamera.ProjectionMatrix);
            }

            #endregion

            #region Render UI
            m_uiRenderer.Draw((float)gameTime.ElapsedGameTime.TotalMilliseconds, true, false);
            #endregion

            //GraphicsDevice.SetRenderTargets(targets);

            //GraphicsDevice.BlendState = BlendState.Opaque;
            //GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            _frameCounter++;

            _elapsedTime += gameTime.ElapsedGameTime;

            if (_elapsedTime >= TimeSpan.FromSeconds(1))
            {
                _elapsedTime -= TimeSpan.FromSeconds(1);
                _frameRate = _frameCounter;
                _frameCounter = 0;
            }

            //Game.Window.Title = m_sceneLightsList.Count.ToString() + " lights at " + _frameRate.ToString() + " FPS";

            //base.Draw(gameTime);
        }

        #endregion

        #region Load Scene

        /// <summary>
        /// Loads a scene from a given xml file.
        /// </summary>
        /// <param name="filename">The XML file, which should be loaded.</param>
        /// <param name="bStart">Enables the scene physics after the scene has been loaded.</param>
        public void LoadSceneGraph(string filename, bool bStart)
        {
            XmlDocument xmlDoc = new XmlDocument();

            try
            {
                xmlDoc.Load(filename);
            }
            catch (Exception exp)
            {
#if !DEBUG
                System.Windows.Forms.MessageBox.Show("Failed to load scene from " + filename, "Error", System.Windows.Forms.MessageBoxButtons.OK);
#else           
                throw new Exception(exp.Message);
#endif
            }
             
            //foreach (XmlNode xmlDocNode in xmlDoc.ChildNodes)
            //{
            //    if (xmlDocNode is XmlElement)
            //    {
            //        if (xmlDocNode.Name.Equals("Scene"))
            //        {
            //            foreach (XmlNode xmlNode in xmlDocNode.ChildNodes)
            //            {
            //                if (xmlNode.Name.Equals("Physics"))
            //                {
            //                    // TODO
            //                }
            //                else if (xmlNode.Name.Equals("CurrentCamera"))
            //                {
            //                    // TODO
            //                }
            //                else if (xmlNode.Name.Equals("SceneGraph"))
            //                    foreach (XmlNode sceneXmlNode in xmlNode.ChildNodes)
            //                        RecursiveLoad(this.RootNode, (XmlElement)sceneXmlNode);
            //            }
            //        }
            //    }
            //}

            XmlNode rootNode;

            if (xmlDoc.ChildNodes[1].Name.Equals("Scene"))
            {
                rootNode = xmlDoc.ChildNodes[1] as XmlNode;
                
                this.Clear(false);
            }
            else
            {
#if !DEBUG
                System.Windows.Forms.MessageBox.Show("Failed to load scene from " + filename, "Error", System.Windows.Forms.MessageBoxButtons.OK);
#else
                throw new Exception("Failed to load scene from " + filename);
#endif
                return;
            }
            
            // Scene Attributes
            foreach (XmlAttribute att in rootNode.Attributes)
            {
                if (att.Name.Equals("Name"))
                    this.Name = att.Value;

                if (att.Name.Equals("Renderer"))
                {
                    if (att.Value == "Simple")
                        this.RenderType = RenderType.SimpleRenderer;

                    if (att.Value == "MultiPass")
                        this.RenderType = RenderType.ForwardRenderer;

                    if (att.Value == "DeferredRenderer")
                        this.RenderType = RenderType.DeferredRenderer;
                }

            }
            
            // Scene Content
            foreach (XmlNode xmlNode in rootNode.ChildNodes)
            {
                if (xmlNode.Name.Equals("Physics"))
                {
                    foreach(XmlAttribute att in xmlNode.Attributes)
                        if (att.Name.Equals("Gravity"))
                            this.Physics.ForceUpdater.Gravity = Helpers.StringToVector3(att.Value);
                }
                else if (xmlNode.Name.Equals("SceneObjects"))
                {
                    foreach (XmlNode sceneXmlNode in xmlNode.ChildNodes)
                    {
                        #region Cameras
                        if (sceneXmlNode.Name == "Cameras")
                        {
                            foreach (XmlNode xmlCam in sceneXmlNode.ChildNodes)
                            {
                                CameraObject camera = new CameraObject(Helpers.StringToVector3(xmlCam.Attributes["Position"].Value), Helpers.StringToVector3(xmlCam.Attributes["Target"].Value));

                                camera.Orientation = Helpers.StringToQuad(xmlCam.Attributes["Orientation"].Value);

                                camera.FieldOfViewY = float.Parse(xmlCam.Attributes["FOV"].Value, NumberFormatInfo.InvariantInfo);
                                camera.ZNearPlane = float.Parse(xmlCam.Attributes["NearPlane"].Value, NumberFormatInfo.InvariantInfo);
                                camera.ZFarPlane = float.Parse(xmlCam.Attributes["FarPlane"].Value, NumberFormatInfo.InvariantInfo);

                                camera.Enabled = bool.Parse(xmlCam.Attributes["Enable"].Value);
                                camera.Name = xmlCam.Attributes["Name"].Value;

                                camera.ViewFrustum = new BoundingFrustum(camera.ProjectionMatrix);

                                this.Add(camera);

                                if (xmlCam.Attributes["IsActive"].Value == "true")
                                    m_currentCamera = camera;
                            }
                        }
                        #endregion

                        #region Lights
                        if (sceneXmlNode.Name == "Lights")
                        {
                            foreach (XmlNode xmlLight in sceneXmlNode.ChildNodes)
                            {
                                LightType type;

                                switch (xmlLight.Attributes["Type"].Value)
                                {
                                    case "Directional": type = LightType.Directional; break;
                                    case "Point": type = LightType.Point; break;
                                    case "SpotLight": type = LightType.SpotLight; break;
                                    default: type = LightType.Directional; break;
                                }

                                LightObject light = new LightObject(type, Helpers.StringToVector3(xmlLight.Attributes["Position"].Value),
                                                            Helpers.StringToVector3(xmlLight.Attributes["Direction"].Value),
                                                            float.Parse(xmlLight.Attributes["Range"].Value, NumberFormatInfo.InvariantInfo),
                                                            new Color(Helpers.StringToVector4(xmlLight.Attributes["Diffuse"].Value)),
                                                            new Color(Helpers.StringToVector4(xmlLight.Attributes["Specular"].Value)));

                                light.Orientation = Helpers.StringToQuad(xmlLight.Attributes["Orientation"].Value);
                                light.Scale = Helpers.StringToVector3(xmlLight.Attributes["Scale"].Value);
                                light.Source.Falloff = float.Parse(xmlLight.Attributes["Falloff"].Value, NumberFormatInfo.InvariantInfo);
                                light.Source.InnerConeAngle = float.Parse(xmlLight.Attributes["InnerCone"].Value, NumberFormatInfo.InvariantInfo);
                                light.Source.OuterConeAngle = float.Parse(xmlLight.Attributes["OuterCone"].Value, NumberFormatInfo.InvariantInfo);

                                light.Source.Enabled = bool.Parse(xmlLight.Attributes["Enable"].Value);
                                light.Name = xmlLight.Attributes["Name"].Value;

                                this.Add(light);
                            }
                        }
                        #endregion

                        #region Objects
                        if (sceneXmlNode.Name == "Objects")
                        {
                            foreach (XmlNode xmlObj in sceneXmlNode.ChildNodes)
                            {
                                if (xmlObj.Name == "BoxObject")
                                {
                                    BoxObject box = new BoxObject(Helpers.StringToVector3(xmlObj.Attributes["Position"].Value),
                                                                  Helpers.StringToVector3(xmlObj.Attributes["ModelShapeParameters"].Value),
                                                                  float.Parse(xmlObj.Attributes["Mass"].Value));

                                    box.Orientation = Helpers.StringToQuad(xmlObj.Attributes["Orientation"].Value);
                                    box.Scale = Helpers.StringToVector3(xmlObj.Attributes["Scale"].Value);

                                    box.Name = xmlObj.Attributes["Name"].Value;
                                    //box.Enabled = bool.Parse(xmlNode.Attributes["Enable"].Value);

                                    this.Add(box);

                                    // Apply the physical scaling
                                    (box.Physics as BEPUphysics.Entities.Prefabs.Box).Width = box.Scale.X;
                                    (box.Physics as BEPUphysics.Entities.Prefabs.Box).Height = box.Scale.Y;
                                    (box.Physics as BEPUphysics.Entities.Prefabs.Box).Length = box.Scale.Z;

                                    // Finally "reinitialize" the collision shape
                                    if (box.Physics.IsDynamic)
                                        box.Physics.BecomeDynamic(float.Parse(xmlObj.Attributes["Mass"].Value));
                                    else
                                        box.Physics.BecomeKinematic();
                                }
                                else if (xmlObj.Name == "SphereObject")
                                {
                                    Vector3 parameters = Helpers.StringToVector3(xmlObj.Attributes["ModelShapeParameters"].Value);
                                    SphereObject sphere = new SphereObject(Helpers.StringToVector3(xmlObj.Attributes["Position"].Value),
                                                                  parameters.X, (int)parameters.Y, (int)parameters.Z,
                                                                  float.Parse(xmlObj.Attributes["Mass"].Value));

                                    sphere.Orientation = Helpers.StringToQuad(xmlObj.Attributes["Orientation"].Value);
                                    sphere.Scale = Helpers.StringToVector3(xmlObj.Attributes["Scale"].Value);

                                    sphere.Name = xmlObj.Attributes["Name"].Value;
                                    //sphere.Enabled = bool.Parse(xmlNode.Attributes["Enable"].Value);

                                    this.Add(sphere);

                                    // Apply the physical scaling
                                    (sphere.Physics as BEPUphysics.Entities.Prefabs.Sphere).Radius = sphere.Scale.X;
                                    (sphere.Physics as BEPUphysics.Entities.Prefabs.Sphere).Radius = sphere.Scale.Y;
                                    (sphere.Physics as BEPUphysics.Entities.Prefabs.Sphere).Radius = sphere.Scale.Z;
                                    
                                    // Finally "reinitialize" the collision shape
                                    if (sphere.Physics.IsDynamic)
                                        sphere.Physics.BecomeDynamic(float.Parse(xmlObj.Attributes["Mass"].Value));
                                    else
                                        sphere.Physics.BecomeKinematic();
                                }
                                else if (xmlObj.Name == "CylinderObject")
                                {
                                    Vector3 parameters = Helpers.StringToVector3(xmlObj.Attributes["ModelShapeParameters"].Value);
                                    CylinderObject cylinder = new CylinderObject(Helpers.StringToVector3(xmlObj.Attributes["Position"].Value),
                                                                  parameters.X, (int)parameters.Y, (int)parameters.Z,
                                                                  float.Parse(xmlObj.Attributes["Mass"].Value));

                                    cylinder.Orientation = Helpers.StringToQuad(xmlObj.Attributes["Orientation"].Value);
                                    cylinder.Scale = Helpers.StringToVector3(xmlObj.Attributes["Scale"].Value);
                                                                      
                                    cylinder.Name = xmlObj.Attributes["Name"].Value;
                                    //sphere.Enabled = bool.Parse(xmlNode.Attributes["Enable"].Value);
                                                                        
                                    this.Add(cylinder);

                                    // Apply the physical scaling
                                    (cylinder.Physics as BEPUphysics.Entities.Prefabs.Cylinder).Radius = cylinder.Scale.X;
                                    (cylinder.Physics as BEPUphysics.Entities.Prefabs.Cylinder).Radius = cylinder.Scale.Y;
                                    (cylinder.Physics as BEPUphysics.Entities.Prefabs.Cylinder).Height = cylinder.Scale.Z;
                                    
                                    // Finally "reinitialize" the collision shape
                                    if (cylinder.Physics.IsDynamic)
                                        cylinder.Physics.BecomeDynamic(float.Parse(xmlObj.Attributes["Mass"].Value));
                                    else
                                        cylinder.Physics.BecomeKinematic();
                                }
                                else if (xmlObj.Name == "CapsuleObject")
                                {
                                    Vector3 parameters = Helpers.StringToVector3(xmlObj.Attributes["ModelShapeParameters"].Value);
                                    CapsuleObject capsule = new CapsuleObject(Helpers.StringToVector3(xmlObj.Attributes["Position"].Value),
                                                                  parameters.X, (int)parameters.Y, (int)parameters.Z,
                                                                  float.Parse(xmlObj.Attributes["Mass"].Value));

                                    capsule.Orientation = Helpers.StringToQuad(xmlObj.Attributes["Orientation"].Value);
                                    capsule.Scale = Helpers.StringToVector3(xmlObj.Attributes["Scale"].Value);
                                    
                                    capsule.Name = xmlObj.Attributes["Name"].Value;
                                    //sphere.Enabled = bool.Parse(xmlNode.Attributes["Enable"].Value);

                                    this.Add(capsule);

                                    // Apply the physical scaling
                                    (capsule.Physics as BEPUphysics.Entities.Prefabs.Capsule).Radius = capsule.Scale.X;
                                    (capsule.Physics as BEPUphysics.Entities.Prefabs.Capsule).Radius = capsule.Scale.Y;
                                    (capsule.Physics as BEPUphysics.Entities.Prefabs.Capsule).Length = capsule.Scale.Z;


                                    // Finally "reinitialize" the collision shape
                                    if (capsule.Physics.IsDynamic)
                                        capsule.Physics.BecomeDynamic(float.Parse(xmlObj.Attributes["Mass"].Value));
                                    else
                                        capsule.Physics.BecomeKinematic();
                                }
                                else if (xmlObj.Name == "ConeObject")
                                {
                                    Vector3 parameters = Helpers.StringToVector3(xmlObj.Attributes["ModelShapeParameters"].Value);
                                    ConeObject cone = new ConeObject(Helpers.StringToVector3(xmlObj.Attributes["Position"].Value),
                                                                  parameters.X, (int)parameters.Y, (int)parameters.Z,
                                                                  float.Parse(xmlObj.Attributes["Mass"].Value));

                                    cone.Orientation = Helpers.StringToQuad(xmlObj.Attributes["Orientation"].Value);
                                    cone.Scale = Helpers.StringToVector3(xmlObj.Attributes["Scale"].Value);

                                    
                                    cone.Name = xmlObj.Attributes["Name"].Value;
                                    //sphere.Enabled = bool.Parse(xmlNode.Attributes["Enable"].Value);
                                    
                                    this.Add(cone);

                                    // Apply the physical scaling
                                    (cone.Physics as BEPUphysics.Entities.Prefabs.Cone).Radius = cone.Scale.X;
                                    (cone.Physics as BEPUphysics.Entities.Prefabs.Cone).Radius = cone.Scale.Y;
                                    (cone.Physics as BEPUphysics.Entities.Prefabs.Cone).Height = cone.Scale.Z;
                                    
                                    // Finally "reinitialize" the collision shape
                                    if (cone.Physics.IsDynamic)
                                        cone.Physics.BecomeDynamic(float.Parse(xmlObj.Attributes["Mass"].Value));
                                    else
                                        cone.Physics.BecomeKinematic();
                                }
                                else if (xmlObj.Name == "ModelObject")
                                {
                                    Vector3 parameters = Helpers.StringToVector3(xmlObj.Attributes["ModelShapeParameters"].Value);
                                    ModelObject model = new ModelObject(Helpers.StringToVector3(xmlObj.Attributes["Position"].Value),
                                                                  Helpers.StringToQuad(xmlObj.Attributes["Orientation"].Value),
                                                                  Helpers.StringToVector3(xmlObj.Attributes["Scale"].Value),
                                                                  (int.Parse(xmlObj.Attributes["CollisionType"].Value) == 0) ? CollisionType.ConvexHull : CollisionType.ExactMesh,
                                                                  "",
                                                                  xmlObj.Attributes["AssetName"].Value,
                                                                  float.Parse(xmlObj.Attributes["Mass"].Value));
                                    
                                    model.Name = xmlObj.Attributes["Name"].Value;
                                    //sphere.Enabled = bool.Parse(xmlNode.Attributes["Enable"].Value);
                                    
                                    this.Add(model);

                                    // Apply the physical scaling
                                    (model.Physics as BEPUphysics.Entities.Prefabs.Cone).Radius = model.Scale.X;
                                    (model.Physics as BEPUphysics.Entities.Prefabs.Cone).Radius = model.Scale.Y;
                                    (model.Physics as BEPUphysics.Entities.Prefabs.Cone).Height = model.Scale.Z;


                                    // Finally "reinitialize" the collision shape
                                    if (model.Physics.IsDynamic)
                                        model.Physics.BecomeDynamic(float.Parse(xmlObj.Attributes["Mass"].Value));
                                    else
                                        model.Physics.BecomeKinematic();
                                }
                            }
                        }
                        #endregion

                        #region Particles
                        if (sceneXmlNode.Name == "Particles")
                        {
                            // TODO
                        }
                        #endregion

                        #region Controllers
                        if (sceneXmlNode.Name == "Controllers")
                        {
                            // TODO
                        }
                        #endregion
                    }
                }
            }

            // Reactive the scene
            m_bPausePhysics = !bStart;
        }

        #endregion
        
        #region Save Scene

        /// <summary>
        /// Saves the current scene arrangement to the given file in XML.
        /// </summary>
        public void SaveSceneGraph(string filename)
        {
            XmlDocument xmlDoc = new XmlDocument();
            XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);

            xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);

            // Scene node
            XmlElement xmlRootNode = xmlDoc.CreateElement("Scene");

            XmlAttribute xmlSceneNameAtt = xmlDoc.CreateAttribute("Name");
            xmlSceneNameAtt.InnerText = this.Name;
            xmlDoc.AppendChild(xmlRootNode);

            XmlAttribute xmlSceneRendererAtt = xmlDoc.CreateAttribute("Renderer");
            xmlSceneNameAtt.InnerText = m_renderType.ToString();
            xmlDoc.AppendChild(xmlRootNode);

            // Physics
            XmlElement xmlPhysicsNode = xmlDoc.CreateElement("Physics");
            xmlRootNode.AppendChild(xmlPhysicsNode);

            XmlAttribute xmlPhysicsGravityAtt = xmlDoc.CreateAttribute("Gravity");
            xmlPhysicsGravityAtt.InnerText = m_physicsEngine.ForceUpdater.Gravity.ToString();
            xmlDoc.AppendChild(xmlRootNode);

            XmlElement xmlSceneObjectsNode = xmlDoc.CreateElement("SceneObjects");
            xmlRootNode.AppendChild(xmlSceneObjectsNode);

            //RecursiveSave(xmlSceneObjectsNode, this.RootNode, xmlDoc);

            #region Scene Cameras
            XmlElement xmlCameraNode = xmlDoc.CreateElement("Cameras");
            xmlSceneObjectsNode.AppendChild(xmlCameraNode);

            foreach (CameraObject obj in m_sceneCamerasList)
            {
                XmlNode xmlObjNode = xmlDoc.CreateElement("CameraObject");
                xmlCameraNode.AppendChild(xmlObjNode);

                // Position
                XmlAttribute xmlPosAtt = xmlDoc.CreateAttribute("Position");
                xmlPosAtt.InnerText = Helpers.Vector3ToString(obj.Position);
                xmlObjNode.Attributes.Append(xmlPosAtt);

                // Orientation
                XmlAttribute xmlOriAtt = xmlDoc.CreateAttribute("Orientation");
                xmlOriAtt.InnerText = Helpers.QuadToString(obj.Orientation);
                xmlObjNode.Attributes.Append(xmlOriAtt);

                // Target
                XmlAttribute xmlTargetAtt = xmlDoc.CreateAttribute("Target");
                xmlTargetAtt.InnerText = Helpers.Vector3ToString(obj.Target);
                xmlObjNode.Attributes.Append(xmlTargetAtt);

                // Field of View
                XmlAttribute xmlFOVAtt = xmlDoc.CreateAttribute("FOV");
                xmlFOVAtt.InnerText = obj.FieldOfViewY.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlFOVAtt);
                
                // Near Plane
                XmlAttribute xmlNearPlaneAtt = xmlDoc.CreateAttribute("NearPlane");
                xmlNearPlaneAtt.InnerText = obj.ZNearPlane.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlNearPlaneAtt);

                // Far Plane
                XmlAttribute xmlFarPlaneAtt = xmlDoc.CreateAttribute("FarPlane");
                xmlFarPlaneAtt.InnerText = obj.ZFarPlane.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlFarPlaneAtt);

                // Enabled
                XmlAttribute xmlEnableAtt = xmlDoc.CreateAttribute("Enable");
                xmlEnableAtt.InnerText = obj.Enabled.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlEnableAtt);

                // Name
                XmlAttribute xmlNameAtt = xmlDoc.CreateAttribute("Name");
                xmlNameAtt.InnerText = obj.Name.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlNameAtt);

                // If this is the active camera, save this property!
                XmlAttribute xmlActiveAtt = xmlDoc.CreateAttribute("IsActive");
                xmlActiveAtt.InnerText = (obj == m_currentCamera) ? "true" : "false";
                xmlObjNode.Attributes.Append(xmlActiveAtt);

                //xmlChildNode = xmlDoc.CreateElement("Children");
                //xmlObjNode.AppendChild(xmlChildNode);
            }
            #endregion

            #region Scene Lights
            XmlElement xmlLightsNode = xmlDoc.CreateElement("Lights");
            xmlSceneObjectsNode.AppendChild(xmlLightsNode);

            foreach (LightObject obj in m_sceneLightsList)
            {
                XmlNode xmlObjNode = xmlDoc.CreateElement("LightObject");
                xmlLightsNode.AppendChild(xmlObjNode);

                // Type
                XmlAttribute xmlTypeAtt = xmlDoc.CreateAttribute("Type");
                xmlTypeAtt.InnerText = obj.Source.Type.ToString();
                xmlObjNode.Attributes.Append(xmlTypeAtt);

                // Position
                XmlAttribute xmlPosAtt = xmlDoc.CreateAttribute("Position");
                xmlPosAtt.InnerText = Helpers.Vector3ToString(obj.Position);
                xmlObjNode.Attributes.Append(xmlPosAtt);

                // Orientation
                XmlAttribute xmlOriAtt = xmlDoc.CreateAttribute("Orientation");
                xmlOriAtt.InnerText = Helpers.QuadToString(obj.Orientation);
                xmlObjNode.Attributes.Append(xmlOriAtt);

                // Scale
                XmlAttribute xmlScaleAtt = xmlDoc.CreateAttribute("Scale");
                xmlScaleAtt.InnerText = Helpers.Vector3ToString(obj.Scale);
                xmlObjNode.Attributes.Append(xmlScaleAtt);

                // Range
                XmlAttribute xmlRangeAtt = xmlDoc.CreateAttribute("Range");
                xmlRangeAtt.InnerText = obj.Source.Range.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlRangeAtt);

                // Direction
                XmlAttribute xmlDirectionAtt = xmlDoc.CreateAttribute("Direction");
                xmlDirectionAtt.InnerText = Helpers.Vector3ToString(obj.Source.Direction);
                xmlObjNode.Attributes.Append(xmlDirectionAtt);

                // Diffuse Color
                XmlAttribute xmlMDiffuseAtt = xmlDoc.CreateAttribute("Diffuse");
                xmlMDiffuseAtt.InnerText = Helpers.Vector4ToString(obj.Source.Diffuse);
                xmlObjNode.Attributes.Append(xmlMDiffuseAtt);

                // Specular Color
                XmlAttribute xmlSpecularAtt = xmlDoc.CreateAttribute("Specular");
                xmlSpecularAtt.InnerText = Helpers.Vector4ToString(obj.Source.Specular);
                xmlObjNode.Attributes.Append(xmlSpecularAtt);

                // Falloff
                XmlAttribute xmlFalloffAtt = xmlDoc.CreateAttribute("Falloff");
                xmlFalloffAtt.InnerText = obj.Source.Falloff.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlFalloffAtt);

                // Inner Cone Angle
                XmlAttribute xmlInnerConeAtt = xmlDoc.CreateAttribute("InnerCone");
                xmlInnerConeAtt.InnerText = obj.Source.InnerConeAngle.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlInnerConeAtt);

                // Outer Cone Angle
                XmlAttribute xmlOuterConeAtt = xmlDoc.CreateAttribute("OuterCone");
                xmlOuterConeAtt.InnerText = obj.Source.InnerConeAngle.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlOuterConeAtt);

                // Enabled
                XmlAttribute xmlEnableAtt = xmlDoc.CreateAttribute("Enable");
                xmlEnableAtt.InnerText = obj.Source.Enabled.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlEnableAtt);

                // Name
                XmlAttribute xmlNameAtt = xmlDoc.CreateAttribute("Name");
                xmlNameAtt.InnerText = obj.Name.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlNameAtt);

                //xmlChildNode = xmlDoc.CreateElement("Children");
                //xmlObjNode.AppendChild(xmlChildNode);
            }
            #endregion

            #region Scene Objects
            XmlElement xmlObjectsNode = xmlDoc.CreateElement("Objects");
            xmlSceneObjectsNode.AppendChild(xmlObjectsNode);

            foreach (SceneObject obj in m_sceneObjectsList)
            {
                XmlNode xmlObjNode = xmlDoc.CreateElement(obj.Type);
                xmlObjectsNode.AppendChild(xmlObjNode);

                // Name
                XmlAttribute xmlNameAtt = xmlDoc.CreateAttribute("Name");
                xmlNameAtt.InnerText = obj.Name.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlNameAtt);

                // Position
                XmlAttribute xmlPosAtt = xmlDoc.CreateAttribute("Position");
                xmlPosAtt.InnerText = Helpers.Vector3ToString(obj.Position);
                xmlObjNode.Attributes.Append(xmlPosAtt);

                // Orientation
                XmlAttribute xmlOriAtt = xmlDoc.CreateAttribute("Orientation");
                xmlOriAtt.InnerText = Helpers.QuadToString(obj.Orientation);
                xmlObjNode.Attributes.Append(xmlOriAtt);

                // Scale
                XmlAttribute xmlScaleAtt = xmlDoc.CreateAttribute("Scale");
                xmlScaleAtt.InnerText = Helpers.Vector3ToString(obj.Scale);
                xmlObjNode.Attributes.Append(xmlScaleAtt);

                // Model parameters
                XmlAttribute xmlModelAtt = xmlDoc.CreateAttribute("ModelShapeParameters");
                xmlModelAtt.InnerText = obj.ShapeParameters;
                xmlObjNode.Attributes.Append(xmlModelAtt);

                // Mass
                XmlAttribute xmlMassAtt = xmlDoc.CreateAttribute("Mass");

                if (obj.Physics.IsDynamic)
                    xmlMassAtt.InnerText = obj.Physics.Mass.ToString();
                else
                    xmlMassAtt.InnerText = "0";

                xmlObjNode.Attributes.Append(xmlMassAtt);

                
                //// Shader
                //XmlAttribute xmlShaderAtt = xmlDoc.CreateAttribute("Shader");
                //xmlShaderAtt.InnerText = TypeDescriptor.GetClassName(obj.Shader);
                //xmlObjNode.Attributes.Append(xmlShaderAtt);

                // Shader technique
                XmlAttribute xmlShaderTechniqueAtt = xmlDoc.CreateAttribute("Shader");
                xmlShaderTechniqueAtt.InnerText = obj.Model.ShaderTechnique;
                xmlObjNode.Attributes.Append(xmlShaderTechniqueAtt);

                if (obj is ModelObject)
                {
                    // Collision Type
                    XmlAttribute xmlCollisionTypeAtt = xmlDoc.CreateAttribute("CollisionType");
                    xmlCollisionTypeAtt.InnerText = (obj as ModelObject).CollisionType.ToString();
                    xmlObjNode.Attributes.Append(xmlCollisionTypeAtt);

                    // AssetName
                    XmlAttribute xmlAssetNameAtt = xmlDoc.CreateAttribute("AssetName");
                    xmlAssetNameAtt.InnerText = (obj as ModelObject).AssetName;
                    xmlObjNode.Attributes.Append(xmlAssetNameAtt);
                }

                //// Enabled
                //XmlAttribute xmlEnableAtt = xmlDoc.CreateAttribute("Enable");
                //xmlEnableAtt.InnerText = obj.Enabled.ToString(NumberFormatInfo.InvariantInfo);
                //xmlObjNode.Attributes.Append(xmlEnableAtt);

                //xmlChildNode = xmlDoc.CreateElement("Children");
                //xmlObjNode.AppendChild(xmlChildNode);
            }
            #endregion

            #region Scene Particles
            XmlElement xmlParticlesNode = xmlDoc.CreateElement("Particles");
            xmlSceneObjectsNode.AppendChild(xmlParticlesNode);

            foreach (ParticleObject obj in m_sceneParticleList)
            {
                // TODO
            }
            #endregion

            #region Scene Controllers
            XmlElement xmlControllerNode = xmlDoc.CreateElement("Controllers");
            xmlSceneObjectsNode.AppendChild(xmlControllerNode);

            foreach (Controller obj in m_sceneMarkerControllersList)
            {
                XmlNode xmlObjNode = xmlDoc.CreateElement(obj.Type);
                xmlControllerNode.AppendChild(xmlObjNode);

                // Name
                XmlAttribute xmlNameAtt = xmlDoc.CreateAttribute("Name");
                xmlNameAtt.InnerText = obj.Name.ToString(NumberFormatInfo.InvariantInfo);
                xmlObjNode.Attributes.Append(xmlNameAtt);

                // Position
                XmlAttribute xmlPosAtt = xmlDoc.CreateAttribute("Position");
                xmlPosAtt.InnerText = Helpers.Vector3ToString(obj.Position);
                xmlObjNode.Attributes.Append(xmlPosAtt);

                // Orientation
                XmlAttribute xmlOriAtt = xmlDoc.CreateAttribute("Orientation");
                xmlOriAtt.InnerText = Helpers.QuadToString(obj.Orientation);
                xmlObjNode.Attributes.Append(xmlOriAtt);

                // Scale
                XmlAttribute xmlScaleAtt = xmlDoc.CreateAttribute("Scale");
                xmlScaleAtt.InnerText = Helpers.Vector3ToString(obj.Scale);
                xmlObjNode.Attributes.Append(xmlScaleAtt);
            }
            #endregion
            
            try
            {
                xmlDoc.Save(filename);
            }
            catch (Exception exp)
            {
#if !DEBUG
                System.Windows.Forms.MessageBox.Show("Failed to save the scene as " + filename, "Error", System.Windows.Forms.MessageBoxButtons.OK);
#else
                throw new Exception(exp.Message);
#endif
            }
        }
            
        #endregion


        #region Public Methods

        /// <summary>
        /// Adds the given object to the scene.
        /// </summary>
        /// <param name="obj">The object to be added.</param>
        public void Add(object obj)
        {
            if (obj is SceneObject)
            {
                m_physicsEngine.Add(((SceneObject)obj).Physics);
                m_physicsEngine.Add(((SceneObject)obj).m_grabber);

                m_sceneObjectsList.Add(obj as SceneObject);

                (obj as SceneObject).Scene = this;

                // Remember the collision mesh
                this.CollidersList.Add((obj as SceneObject).Physics, (obj as SceneObject));
                m_collisionMeshRenderer.Add(((SceneObject)obj).Physics);
            }

            if (obj is LightObject)
            {
                m_sceneLightsList.Add(obj as LightObject);
            }

            if (obj is CameraObject)
            {
                m_sceneCamerasList.Add(obj as CameraObject);
            }

            if (obj is ISpaceObject)
            {
                Type t = obj.GetType();
                (obj as ISpaceObject).Tag = t.Name.ToString() + Core.GetNextNodeID().ToString();
                m_physicsEngine.Add(obj as ISpaceObject);
                this.m_scenePhysicsList.Add(obj as ISpaceObject);
            }

            if (obj is ParticleObject)
            {
                m_sceneParticleList.Add(obj as ParticleObject);
            }

            if (obj is Controller)
                m_sceneControllersList.Add(obj as Controller);

            if (obj is SoundObject)
            {
                (obj as SoundObject).Instance.Apply3D(m_audioListener, m_audioEmitter);
                m_sceneSoundsList.Add(obj as SoundObject);
            }

            if (obj is Text3D)
            {
                m_sceneText3D.Add(obj as Text3D);
            }

            if (this.ObjectAdded != null && obj is ITransformable)
            {
                this.ObjectAdded(this, new SceneChangedEventArgs(obj as ITransformable));
            }
        }

        /// <summary>
        /// Determines whether the given object is still part of the scene.
        /// </summary>
        /// <param name="obj">The object, which should be part of the scene</param>
        /// <returns>Returns true, if the scene contains the given object</returns>
        public bool Contains(object obj)
        {
            if (obj is SceneObject)
            {
                return m_sceneObjectsList.Contains(obj as SceneObject);
            }
            else if (obj is LightObject)
            {
                return m_sceneLightsList.Contains(obj as LightObject);
            }
            else if (obj is CameraObject)
            {
                return m_sceneCamerasList.Contains(obj as CameraObject);
            }
            else if (obj is ISpaceObject)
            {
                return m_physicsEngine.Entities.Contains(obj as ISpaceObject);
            }
            else if (obj is ParticleObject)
            {
                return m_sceneParticleList.Contains(obj as ParticleObject);
            }
            else if (obj is Controller)
            {
                return m_sceneControllersList.Contains(obj as Controller);
            }
            else if (obj is SoundObject)
            {
                return m_sceneSoundsList.Contains(obj as SoundObject);
            }
            else if (obj is Text3D)
            {
                return m_sceneText3D.Contains(obj as Text3D);
            }

            return false;
        }

        /// <summary>
        /// Removes the given object from the current scene.
        /// </summary>
        /// <param name="obj">The object, which should be removed.</param>
        public void Remove(object obj)
        {
            if (obj is SceneObject)
            {
                m_sceneObjectsList.Remove(obj as SceneObject);

                m_physicsEngine.Remove(((SceneObject)obj).Physics);
                m_physicsEngine.Remove(((SceneObject)obj).m_grabber);
                this.CollidersList.Remove((obj as SceneObject).Physics);
                m_collisionMeshRenderer.Remove(((SceneObject)obj).Physics);
            }

            if (obj is LightObject)
            {
                m_sceneLightsList.Remove(obj as LightObject);
            }

            if (obj is CameraObject)
            {
                m_sceneCamerasList.Remove(obj as CameraObject);
            }

            if (obj is ISpaceObject)
            {
                m_physicsEngine.Remove(obj as ISpaceObject);
                this.m_scenePhysicsList.Remove(obj as ISpaceObject);
            }

            if (obj is ParticleObject)
            {
                m_sceneParticleList.Remove(obj as ParticleObject);
            }

            if (obj is Controller)
            {
                m_sceneControllersList.Remove(obj as Controller);
            }

            if (obj is SoundObject)
            {
                m_sceneSoundsList.Remove(obj as SoundObject);
            }

            if (obj is Text3D)
            {
                m_sceneText3D.Remove(obj as Text3D);
            }


            if (this.ObjectRemoved != null && obj is ITransformable)
            {
                this.ObjectRemoved(this, new SceneChangedEventArgs(obj as ITransformable));
            }
        }

        /// <summary>
        /// Removes all scene objects from the current scene. This removes
        /// only the physical objects! Cameras, Lights, Particles and so on
        /// are NOT removed!
        /// </summary>
        public void RemoveAllSceneObjects()
        {
            // First remove all physical objects
            foreach(SceneObject obj in m_sceneObjectsList)
            {
                m_physicsEngine.Remove(obj.Physics);
                m_physicsEngine.Remove(obj.m_grabber);
            }

            // Then, clear the scene object list
            m_sceneObjectsList.Clear();
            m_scenePhysicsList.Clear();
            this.CollidersList.Clear();
        }

        /// <summary>
        /// Initializes optical marker tracking and creates a controller for each optical marker
        /// </summary>
        /// <param name="settings">Parameter definition of the video camera, which should be used.</param>
        /// <param name="configFiles">List of optical marker configuration files</param>
        /// <returns>Returns a list of controller, where every controller represents the optical marker of the configFiles list at the same index.</returns>
        public List<ARMarkerController> InitMarkerTracking(VideoCamera settings, List<string> configFiles)
        {
            DirectShowCapture captureDevice = new DirectShowCapture();
            captureDevice.InitVideoCapture(settings.CameraID, settings.FrameRate, settings.Resolution, settings.ImageFormat, settings.Grayscale);
            
            // Add this video capture device to the scene so that it can be used for
            // the marker tracker
            AddVideoCaptureDevice(captureDevice);

            IMarkerTracker tracker = null;

            // Create an optical marker tracker that uses ALVAR library
            tracker = new ALVARMarkerTracker();
            ((ALVARMarkerTracker)tracker).MaxMarkerError = 0.02f;
            tracker.InitTracker(captureDevice.Width, captureDevice.Height, settings.CalibrationFile, 1f);

            m_markerTracker = tracker;

            if (m_currentCamera == null)
            {
                CameraObject cam = new CameraObject(Vector3.Zero, Vector3.Zero);

                cam.ViewMatrix = Matrix.CreateLookAt(new Vector3(0, 0, 0), new Vector3(0, 0, -1), new Vector3(0, 1, 0));

                cam.ProjectionMatrix = tracker.CameraProjection;
                
                m_currentCamera = cam;
            }
            else
            {
                m_currentCamera.ProjectionMatrix = tracker.CameraProjection;
            }                        

            // Create an array to hold a list of marker IDs that are used in the marker
            // array configuration (even though these are already specified in the configuration
            // file, ALVAR still requires this array)
            int[] ids = new int[configFiles.Count];
            for (int i = 0; i < ids.Length; i++)
                ids[i] = i;

            foreach (string file in configFiles)
            {
                ARMarkerController marker = new ARMarkerController(tracker, file, ids);
                m_sceneMarkerControllersList.Add(marker);
            }

            //m_markerTrackingThread = new Thread(UpdateTracker);
            //m_markerTrackingThread.Start();
            


            m_bShowCameraImage = true;

            m_bMarkerTrackingInitialized = true;

            return m_sceneMarkerControllersList;
        }

        /// <summary>
        /// Initializes optical marker tracking and creates a controller for each optical marker
        /// </summary>
        /// <param name="calibrationFile">Path of the camera calibration file, which will be passed to the marker tracker.</param>
        /// <param name="configFiles">List of optical marker configuration files</param>
        /// <returns>Returns a list of controller, where every controller represents the optical marker of the configFiles list at the same index.</returns>
        public List<ARMarkerController> InitKinectMarkerTracking(string calibrationFile, List<string> configFiles)
        {
            KinectCapture captureDevice = new KinectCapture();
            captureDevice.InitVideoCapture(0, FrameRate._30Hz, Resolution._640x480, ImageFormat.B8G8R8A8_32, false);
            captureDevice.Width = 640;
            captureDevice.Height = 480;

            // Add this video capture device to the scene so that it can be used for
            // the marker tracker
            AddVideoCaptureDevice(captureDevice);

            IMarkerTracker tracker = null;

            // Create an optical marker tracker that uses ALVAR library
            tracker = new ALVARMarkerTracker();
            ((ALVARMarkerTracker)tracker).MaxMarkerError = 0.02f;
            tracker.InitTracker(captureDevice.Width, captureDevice.Height, calibrationFile, 1f);

            m_markerTracker = tracker;

            if (m_currentCamera == null)
            {
                CameraObject cam = new CameraObject(Vector3.Zero, Vector3.Zero);

                cam.ViewMatrix = Matrix.CreateLookAt(new Vector3(0, 0, 0), new Vector3(0, 0, -1), new Vector3(0, 1, 0));

                cam.ProjectionMatrix = tracker.CameraProjection;

                m_currentCamera = cam;
            }
            else
            {
                m_currentCamera.ProjectionMatrix = tracker.CameraProjection;
            }

            // Create an array to hold a list of marker IDs that are used in the marker
            // array configuration (even though these are already specified in the configuration
            // file, ALVAR still requires this array)
            int[] ids = new int[configFiles.Count];
            for (int i = 0; i < ids.Length; i++)
                ids[i] = i;

            foreach (string file in configFiles)
            {
                ARMarkerController marker = new ARMarkerController(tracker, file, ids);
                m_sceneMarkerControllersList.Add(marker);
            }

            //m_markerTrackingThread = new Thread(UpdateTracker);
            //m_markerTrackingThread.Start();



            m_bShowCameraImage = true;

            m_bMarkerTrackingInitialized = true;

            return m_sceneMarkerControllersList;
        }

        /// <summary>
        /// Enables the Vuzix iWar VR920 stereoscopic video eyewear.
        /// </summary>
        public void InitVuzix()
        {
            m_bStereoMode = true;

            leftViewport = new Viewport();
            leftViewport.X = 0;
            leftViewport.Y = 0;
            leftViewport.Width = Core.Width / 2;
            leftViewport.Height = Core.Height;
            leftViewport.MinDepth = Core.Device.Viewport.MinDepth;
            leftViewport.MaxDepth = Core.Device.Viewport.MaxDepth;

            rightViewport = new Viewport();
            rightViewport.X = Core.Width / 2;
            rightViewport.Y = 0;
            rightViewport.Width = Core.Width / 2;
            rightViewport.Height = Core.Height;
            rightViewport.MinDepth = Core.Device.Viewport.MinDepth;
            rightViewport.MaxDepth = Core.Device.Viewport.MaxDepth;

            // Get an instance of iWearTracker
            iTracker = iWearTracker.Instance;
            // We need to initialize it before adding it to the InputMapper class
            iTracker.Initialize();

            // If not stereo, then we need to set the iWear VR920 to mono mode (by default, it's
            // stereo mode if stereo is available)
            if (m_bStereoMode)
                iTracker.EnableStereo = true;

        }

        /// <summary>
        /// Enables the Playstation Move Controller.
        /// </summary>
        public void InitPSMove()
        {
            m_psMove = new PSMoveCalibration(Game);

            m_psMove.Initialize();

            m_bShowCameraImage = true;
            m_bPSMoveEnabled = true;
        }

        /// <summary>
        /// Enables the Microsoft Kinect with the given runtime options.
        /// </summary>
        /// <param name="options">The runtime options define which data streams of the Kinect should be used.</param>
        public void InitKinect(/*RuntimeOptions options*/)
        {
            // Create a kinect object
            m_kinect = new Kinect(Core.Device);//, options);

            // Enable camera image as background texture
            m_bShowCameraImage = true;

            m_bKinectEnabled = true;
        }


        /// <summary>
        /// Removes all unnessessary threads from the physics engine thread pool and makes
        /// it single threaded by leaving one thread.
        /// </summary>
        public void SetPhysicsSingleThreaded()
        {
            int iCount = m_physicsEngine.ThreadManager.ThreadCount;

            if (iCount > 1)
            {
                for (int i = 1; i < iCount; i++)
                    m_physicsEngine.ThreadManager.RemoveThread();
            }
        }

        /// <summary>
        /// Extends the physics engine thread pool by adding a thread for each processor core.
        /// </summary>
        public void SetPhysicsMultiThreaded()
        {
            if (System.Environment.ProcessorCount > 1)
            {
                for (int i = 1; i < System.Environment.ProcessorCount; i++)
                {
                    m_physicsEngine.ThreadManager.AddThread();
                }
            }
        }

        /// <summary>
        /// Extends the physics engine thread pool by adding the given number of threads.
        /// </summary>
        /// <param name="iThreadsToAdd">Number of threads to be added.</param>
        public void SetPhysicsMultiThreaded(int NumberOfThreads)
        {
            if (NumberOfThreads >= 1)
            {
                for (int i = 0; i < NumberOfThreads; i++)
                {
                    m_physicsEngine.ThreadManager.AddThread();
                }
            }
        }

        /// <summary>
        /// Removes ALL objects in the scene and restart the physics, if this is specified.
        /// </summary>
        /// <param name="bReactivePhysics">Enables the scene physics after the scene has been cleared.</param>
        public void Clear(bool bReactivePhysics = true)
        {
            m_bPausePhysics = true;

            foreach (SceneObject obj in m_sceneObjectsList)
            {
                m_physicsEngine.Remove(obj.Physics);
                m_physicsEngine.Remove(obj.Grabber);
            }

            m_sceneCamerasList.Clear();
            m_sceneControllersList.Clear();
            m_sceneLightsList.Clear();
            m_sceneMarkerControllersList.Clear();
            m_sceneObjectsList.Clear();
            m_sceneParticleList.Clear();

            m_bPausePhysics = !bReactivePhysics;            
        }

        /// <summary>
        /// Finds a scene objects by its name
        /// </summary>
        /// <param name="name">Name of the object to be found</param>
        /// <returns>Returns non-null, if an object was found, otherwise null.</returns>
        public object Find(string name)
        {
            object ret;

            try
            {
                // Search in the objects
                ret = this.m_sceneObjectsList.Find(x => (x.Name == name));
                
                // Break if found
                if(ret != null)
                {
                    return ret;
                }
                
                // Continue searching the lights
                ret = this.m_sceneLightsList.Find(x => (x.Name == name));

                // Break if found
                if (ret != null)
                {
                    return ret;
                }

                // Continue searching the cameras
                ret = this.m_sceneCamerasList.Find(x => (x.Name == name));

                // Break if found
                if (ret != null)
                {
                    return ret;
                }

                // Continue searching the physics objects
                ret = this.m_scenePhysicsList.Find(x => (x.Tag == name));
                
                // Break if found
                if (ret != null)
                {
                    return ret;
                }

                // Continue searching the controllers
                ret = this.m_sceneControllersList.Find(x => (x.Name == name));

                // Break if found
                if (ret != null)
                {
                    return ret;
                }

                // Continue searching the sounds
                ret = this.m_sceneSoundsList.Find(x => (x.Name == name));

                // Break if found
                if (ret != null)
                {
                    return ret;
                }

                // Continue searching the particle
                ret = this.m_sceneParticleList.Find(x => (x.Name == name));

                // Break if found
                if (ret != null)
                {
                    return ret;
                }

                // Continue searching the sounds
                ret = this.m_sceneSoundsList.Find(x => (x.Name == name));

                // Break if found
                if (ret != null)
                {
                    return ret;
                }

                // Continue searching the markers
                ret = this.m_sceneMarkerControllersList.Find(x => (x.Name == name));

                // Break if found
                if (ret != null)
                {
                    return ret;
                }
            }
            catch (Exception e)
            {
                ExceptionManager.Add(e);
            }

            return null;
        }

        /// <summary>
        /// Initializes the speech recognition using the Microsoft Kinect microphon array.
        /// </summary>
        public void InitializeSpeechRecognition()
        {
            RecognizerInfo ri = GetKinectRecognizer();

            if (ri == null)
            {
                ExceptionManager.Add(new Exception(
                    "Failed to load Speech SDK: There was a problem initializing Speech Recognition. Ensure you have the Microsoft Speech SDK installed."));
            }

            try
            {
                sre = new SpeechRecognitionEngine(ri.Id);

                bRunningSpeechRecognition = true;
            }
            catch
            {
                ExceptionManager.Add(new Exception(
                    "Failed to load Speech SDK: There was a problem initializing Speech Recognition. Ensure you have the Microsoft Speech SDK installed and configured."));
            }
        }

        /// <summary>
        /// Start the speech recognition.
        /// </summary>
        public void StartSpeechRecognition()
        {
            try
            {/*
                kinectSource = new KinectAudioSource();
                kinectSource.SystemMode = SystemMode.OptibeamArrayOnly;
                kinectSource.FeatureMode = true;
                kinectSource.AutomaticGainControl = false;
                
                kinectSource.MicArrayMode = MicArrayMode.MicArrayAdaptiveBeam;
                */
                var kinectStream = this.Kinect.Sensor.AudioSource.Start();

                sre.SetInputToAudioStream(kinectStream, new SpeechAudioFormatInfo(
                                                      EncodingFormat.Pcm, 16000, 16, 1,
                                                      32000, 2, null));

                sre.RecognizeAsync(RecognizeMode.Multiple);
            }
            catch
            {
                ExceptionManager.Add(new Exception(
                    "Failed to load Speech SDK: There was a problem initializing the KinectAudioSource. Ensure you have the Kinect SDK installed correctly."));
            }
        }

        #endregion

        #region Private Methods

        private static RecognizerInfo GetKinectRecognizer()
        {
            Func<RecognizerInfo, bool> matchingFunc = r =>
            {
                string value;
                r.AdditionalInfo.TryGetValue("Kinect", out value);
                return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase) && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase);
            };
            return SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault();
        }

        /// <summary>
        /// Updates a given controller.
        /// </summary>
        private void UpdateController(Controller ctrl)
        {                         
            foreach (ITransformable obj in ctrl.Children)
            {
                // Process the child scene objects only if the controller has moved
                if (ctrl.DeltaPos != Vector3.Zero)
                {
                    if (obj is SceneObject)
                    {
                        //if (!(obj as SceneObject).Grabber.IsGrabbing)
                            (obj as SceneObject).MovingPosition/*MoveToPosition*/((obj as SceneObject).Position + ctrl.DeltaPos);
                    }
                    else if (obj is LightObject)
                    {
                        (obj as LightObject).Position += ctrl.DeltaPos;
                    }
                    else if (obj is CameraObject)
                    {
                        (obj as CameraObject).Position += ctrl.DeltaPos;
                    }
                }

                // Process the child scene objects only if the controller has rotated
                if (ctrl.DeltaOri != Quaternion.Identity)
                {
                    if (obj is SceneObject)
                    {
                        //if (!(obj as SceneObject).Grabber.IsGrabbing)
                        {
                            //(obj as SceneObject).RotateTo((obj as SceneObject).Orientation * ctrl.DeltaOri);
                            Matrix orientDelta = Matrix.Identity;
                            Matrix sceneWorld = Matrix.Identity;
                            orientDelta.Forward = sceneWorld.Forward;
                            orientDelta.Up = sceneWorld.Up;
                            orientDelta.Right = sceneWorld.Right;

                            Matrix rotationMatrix = Matrix.CreateFromQuaternion(/*ctrl.DeltaOri);*/ctrl.Orientation);

                            //orientDelta *= Matrix.CreateFromAxisAngle(rotationMatrix.Right, delta);
                            //orientDelta *= Matrix.CreateFromAxisAngle(rotationMatrix.Up, delta);
                            //orientDelta *= Matrix.CreateFromAxisAngle(rotationMatrix.Forward, delta);

                            orientDelta = orientDelta * rotationMatrix;

                            Matrix localOrient = Matrix.CreateFromQuaternion(obj.Orientation);
                            
                            if(ctrl.ActivePivot == Controller.Pivot.Center)
                                localOrient.Translation = obj.Position - ctrl.Position;

                            Matrix newOrient = localOrient * rotationMatrix;//localOrient * orientDelta;

                            if(ctrl.ActivePivot == Controller.Pivot.Center)
                                (obj as SceneObject).MovingPosition/*MoveToPosition*/(newOrient.Translation + ctrl.Position);
                            
                            (obj as SceneObject).RotatingTo/*RotateTo*/(Quaternion.CreateFromRotationMatrix(newOrient));
                        }
                    }
                    else if (obj is LightObject)
                    {
                        (obj as LightObject).Orientation *= ctrl.DeltaOri;
                    }
                    else if (obj is CameraObject)
                    {
                        (obj as CameraObject).Orientation *= ctrl.DeltaOri;
                    }
                }
                    
                // Always process the child controllers. Their movement can be independent from the parent controller movement.
                if (obj is Controller)
                {
                    // Add the current controller's delta to it's child and process it recursivly
                    (obj as Controller).DeltaPos += ctrl.DeltaPos;
                    (obj as Controller).DeltaOri = (obj as Controller).DeltaOri * ctrl.DeltaOri;
                    UpdateController((obj as Controller));
                }
            }

            // Reset the current controller's deltas, because this controller is now processed.
            ctrl.DeltaPos = Vector3.Zero;
            ctrl.DeltaOri = Quaternion.Identity;
        }

        /// <summary>
        /// Renders a texture as scene background. This can be a static or
        /// a camera image.
        /// </summary>
        private void RenderTexture()
        {
            // Now turn off the depth buffer to overwrite the scene with background image
            //if (m_bShowCameraImage || (m_BackgroundTexture != null))                
            {
                //Core.Device.DepthStencilState = DepthStencilState.None;

                
                if (m_bShowCameraImage && m_bPSMoveEnabled || (m_bKinectEnabled == true && m_kinect.ShowCameraImage != Kinect.KinectCameraImage.None) && m_BackgroundTexture != null)
                {
                    // Save old blend state 
                    //BlendState oldState = Core.Device.BlendState;

                    if (m_kinect.ShowCameraImage == Components.Kinect.Kinect.KinectCameraImage.Depth)
                    {
                        m_spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, Core.KinectDepthVisualizer);
                    }
                    else
                    {
                        m_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                    }

                    m_spriteBatch.Draw(m_BackgroundTexture, new Rectangle(0, 0, Core.Width, Core.Height), m_VideoBackgroundColor);
                    m_spriteBatch.End();

                    // Reset old blend state to support alpha blend
                    //Core.Device.BlendState = oldState;
                }
                else if(m_bMarkerTrackingInitialized)
                {
                    while (m_bCopyingVideoImage) { }
                    
                    if (m_bShowCameraImage)
                    {
                        m_bRenderingVideoTexture = true;

                        // Save old blend state 
                        BlendState oldState = Core.Device.BlendState;

                        m_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque);

                        //m_spriteBatch.Draw(m_VideoTexture, new Rectangle(0, 0, Core.Width, Core.Height), new Rectangle(0, 0, m_videoCaptureDevice.Width, m_videoCaptureDevice.Height), m_VideoBackgroundColor, 0, Vector2.Zero, m_videoCaptureDevice.RenderFormat, 0);
                        Rectangle rcDst = new Rectangle(0, 0, Core.Width, Core.Height);
                        Rectangle rcSrc = new Rectangle(0, 0, m_videoCaptureDevice.Width, m_videoCaptureDevice.Height);
                        m_spriteBatch.Draw(m_VideoTexture, rcDst, rcSrc, m_VideoBackgroundColor, 0, Vector2.Zero, m_videoCaptureDevice.RenderFormat, 0);
                            
                        m_spriteBatch.End();

                        // Reset old blend state to support alpha blend
                        Core.Device.BlendState = oldState;

                        m_bRenderingVideoTexture = false; 
                    }
              
                }
                else if (m_BackgroundTexture != null)
                {
                    m_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);//Opaque);
                    m_spriteBatch.Draw(m_BackgroundTexture, new Rectangle(0, 0, Core.Width, Core.Height), m_VideoBackgroundColor);
                    m_spriteBatch.End();
                }
                
                // Now turn on the depth buffer back for normal rendering
                //Core.Device.DepthStencilState = DepthStencilState.Default;

                Core.Device.SamplerStates[0] = SamplerState.LinearWrap;
                Core.Device.Textures[0] = null;
            }
        }

        private void PrepareScene()
        {

        }

        /// <summary>
        /// Renders the different scene object groups.
        /// </summary>
        private void RenderScene()
        {
            //m_game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            //m_game.GraphicsDevice.BlendState = BlendState.AlphaBlend;

            //m_game.GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
            List<SceneObject> deadObjects = new List<SceneObject>();

            foreach (SceneObject obj in m_sceneObjectsList)
            {
                // If enabled, check if the object has reached the death zone. The death 
                // zone is a big bounding box around the scene, where the objects can live.
                // If an object is leaving the box, it should be removed to prevent
                // updating objects which move towards infinity.
                if (m_deathZone != null && (m_deathZone.Min != Vector3.Zero && m_deathZone.Max != Vector3.Zero))
                {
                    if (m_deathZone.Contains(obj.BoundingBox) != ContainmentType.Contains)
                    {
                        deadObjects.Add(obj);
                        continue;
                    }
                }

                // Check the current movement
                if (obj.ControllerMatrix == Matrix.Identity)
                    obj.ValidateMovement();

                // Discard "camera-invisible" objects
                if (!m_currentCamera.ViewFrustum.Intersects(obj.Physics.CollisionInformation.BoundingBox) || !obj.Visible)
                    continue;

                // If the object is transparent, add it to the transparency group. Otherwise to the occuluder group.       
                if (obj.m_renderMat != null)
                {
                    if (obj.m_renderMat.Transparency > 0)
                        m_groupTransparency.Add(obj);
                    else
                        m_groupOcculuder.Add(obj);
                }
                else
                {
                    // If no render material is defined, then the internal material of the model should be used. 
                    // Assume that it's an occuluder. 
                    m_groupOcculuder.Add(obj);
                }
            }

            // Remove all dead objects
            foreach (SceneObject deadObj in deadObjects)
                Remove(deadObj);

            m_uiRenderer.TriangleCount = 0;

            // Render the occuluder- before the transparency group
            RenderGroup(m_groupOcculuder);
            RenderGroup(m_groupTransparency);                       

            // Clear the groups at the end of the frame
            m_groupOcculuder.Clear();
            m_groupTransparency.Clear();
        }

        /// <summary>
        /// Renders a group of scene objects.
        /// </summary>
        private void RenderGroup(List<SceneObject> objList)
        {
            foreach(SceneObject obj in objList)
            {
                Matrix world;

                // Calculate the object's world matrix depending on the physical transformation
                world = Matrix.CreateScale(obj.Scale) * Matrix.CreateFromQuaternion(obj.Orientation) * Matrix.CreateTranslation(obj.Position);

                // Set the render type
                obj.RenderType = this.m_renderType;

                //// If the object was assigned to a controller
                //if (obj.HasController)
                //{
                //    SpriteFont font = Core.Content.Load<SpriteFont>("DebugFont");

                //    // Calculate the additional transformation created by the optical marker tracking
                //    Matrix tmp1, tmp2, tmp3, markerPreTransformation;

                //    // Transform the object's world matrix, because the marker tracking has a different coordinate system orientation
                //    markerPreTransformation = Matrix.Identity;// Matrix.CreateFromYawPitchRoll(0f, 0f, (float)Math.PI / 2) * Matrix.CreateTranslation(-obj.Model.MinimumBoundingBox.Min * obj.Scale / 2); 
                //    tmp1 = world;//Matrix.Multiply(world, markerPreTransformation);
                //    tmp2 = obj.ControllerMatrix;
                //    Matrix.Multiply(ref tmp1, ref tmp2, out tmp3);

                //    //GoblinXNA.UI.UI2D.UI2DRenderer.WriteText(new Vector2(0, 340), "phys: " + tmp1.Translation.ToString(), Color.Red, font, Vector2.One * 0.7f);
                //    //GoblinXNA.UI.UI2D.UI2DRenderer.WriteText(new Vector2(0, 370), "ctrl: " + tmp2.Translation.ToString(), Color.Red, font, Vector2.One * 0.7f);
                //    //GoblinXNA.UI.UI2D.UI2DRenderer.WriteText(new Vector2(0, 400), "p * c: " + tmp3.Translation.ToString(), Color.Red, font, Vector2.One * 0.7f);
                //    //GoblinXNA.UI.UI2D.UI2DRenderer.WriteText(new Vector2(0, 430), "cam: " + m_currentCamera.Position.ToString(), Color.Red, font, Vector2.One * 0.7f);

                //    obj.WorldMatrix = tmp2;// 3;
                //    world = tmp2;// 3;

                //    //Vector3 pos;
                //    //Vector3 scale;
                //    //Quaternion quad;
                //    //world.Decompose(out scale, out quad, out pos);

                //    //obj.Position = pos;
                //    //obj.Orientation = quad;
                //}

                if(obj.Model != null)
                    m_uiRenderer.TriangleCount += obj.Model.TriangleCount;






                //Matrix tmp1 = obj.ControllerMatrix;
                //Matrix tmp2;
                //Matrix.Multiply(ref world, ref tmp1, out tmp2);

                //world = tmp2;
                //obj.WorldMatrix = tmp2;//world;

                obj.WorldMatrix = world;









                #region Special Objects

                // If it's a compound object, this has to be processed first
                if (obj is CompoundObject)
                {
                    Vector3 pos, newPos;
                    RigidTransform localTransform;

                    // Update the positions of all children
                    for (int i = 0; i < (obj as CompoundObject).Children.Count; i++)
                    {
                        localTransform = (obj as CompoundObject).m_compoundbody.Shapes[i].LocalTransform;

                        // The new position is the compound origin plus the rotated local position
                        (obj as CompoundObject).Children[i].Position = (obj as CompoundObject).m_compoundbody.Position + Vector3.Transform(localTransform.Position, (obj as CompoundObject).m_compoundbody.Orientation);

                        (obj as CompoundObject).Children[i].UseLocalOrientation = false;
                        (obj as CompoundObject).Children[i].Orientation = (obj as CompoundObject).m_compoundbody.Orientation * (obj as CompoundObject).Children[i].LocalOrientation;
                    }

                    RenderGroup((obj as CompoundObject).Children);

                    // The compound object "itself" has nothing which can be rendered
                    continue;
                }
                else
                {
                    obj.UseLocalOrientation = true;
                }

                if (obj is ModelObject)
                {
                    Vector3 translation = Matrix3X3.Transform(obj.Physics.CollisionInformation.LocalPosition, obj.Physics.BufferedStates.InterpolatedStates.OrientationMatrix);
                    translation += obj.Physics.BufferedStates.InterpolatedStates.Position;
                    Matrix worldTransform = Matrix3X3.ToMatrix4X4(obj.Physics.BufferedStates.InterpolatedStates.OrientationMatrix);
                    worldTransform.Translation = translation;

                    obj.WorldMatrix = worldTransform;
                }

                // If it's a rigged model, this has to be rendered independently from the renderers
                if (obj is RiggedModel)
                {
                    obj.Draw(obj.WorldMatrix, EnableLighting, m_currentCamera);

                    continue;
                }

                #endregion

                if (m_bStereoMode)
                {
                    //if (m_bRenderLeftEye)
                    //    world = Matrix.Multiply(world, Matrix.CreateTranslation(new Vector3(-m_currentCamera.InterpupillaryDistance, 0, 0)));
                    //else
                    //    world = Matrix.Multiply(world, Matrix.CreateTranslation(new Vector3(m_currentCamera.InterpupillaryDistance, 0, 0)));
                }

                //GoblinXNA.UI.UI2D.UI2DRenderer.WriteText(new Vector2(0, 460), "obj: " + obj.WorldMatrix.Translation.ToString(), Color.White, font, Vector2.One * 0.7f);

                if (m_renderType == RenderType.SimpleRenderer)
                {
                    Core.Device.DepthStencilState = DepthStencilState.Default;

                    effect.View = m_currentCamera.ViewMatrix;
                    effect.Projection = m_currentCamera.ProjectionMatrix;
                    effect.World = world;

                    effect.DiffuseColor = new Vector3(obj.RenderMaterial.Diffuse.X, obj.RenderMaterial.Diffuse.Y, obj.RenderMaterial.Diffuse.Z);
                    effect.SpecularColor = new Vector3(obj.RenderMaterial.Specular.X, obj.RenderMaterial.Specular.Y, obj.RenderMaterial.Specular.Z);
                    effect.SpecularPower = obj.RenderMaterial.SpecularPower;
                    effect.Alpha = 1f-obj.RenderMaterial.Transparency;

                    if (obj.RenderMaterial.Texture != null)
                    {
                        effect.Texture = obj.RenderMaterial.Texture;
                        effect.TextureEnabled = true;
                    }
                    else if (!(obj is ModelObject))
                    {
                        effect.Texture = null;
                        effect.TextureEnabled = false;
                    }


                    if (EnableLighting && obj.RenderMaterial.EnableLighting)
                    {
                        effect.EnableDefaultLighting();
                    }

                    // Determine if this object should be lightend
                    effect.LightingEnabled = (EnableLighting && obj.RenderMaterial.EnableLighting);

                    if (obj.RenderMaterial.FogEnable)
                    {
                        effect.FogEnabled = true;
                        effect.FogColor = obj.RenderMaterial.FogColor;
                        effect.FogStart = obj.RenderMaterial.FogStart;
                        effect.FogEnd = obj.RenderMaterial.FogEnd;
                    }
                    else
                    {
                        effect.FogEnabled = false;
                    }

                    foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                    {
                        pass.Apply();
                        
                        obj.Draw(world, EnableLighting, m_currentCamera);//RenderDelegate();
                    }
                    
                }
                else if (m_renderType == RenderType.ForwardRenderer)
                {
#if OLD
                    obj.m_shader.SetParameters(m_currentCamera);
                    obj.m_shader.SetParameters(obj.RenderMaterial);
                    obj.m_shader.SetParameters(m_sceneLightsList);
                    //obj.Update(gameTime);

                    obj.Shader.Render(world, null, obj.RenderDelegate, EnableLighting);
#else
                    m_unifiedShader.SetParameters(m_currentCamera);

                    m_unifiedShader.SetParameters(obj.RenderMaterial);
                    
                    m_unifiedShader.SetParameters(m_sceneLightsList);

                    // THIS IS IMPORTANT:
                    // Adapt the graphical mesh to the collision mesh using the intial offset
                    Matrix newWorld = Matrix.CreateTranslation(-obj.m_graphicsPhysOffset) * world;//obj.WorldMatrix;                    
                    if(obj is ModelObject)
                        m_unifiedShader.Render(newWorld, null, delegate
                        {
                            foreach (ModelMesh mesh in ((MeshModel)((SceneObject)obj).Model).Mesh)
                            {
                                foreach (ModelMeshPart part in mesh.MeshParts)
                                {
                                    //part.Effect.CurrentTechnique.Passes[0].Apply();
                                    //m_unifiedShader.colorMapTexture.SetValue(part.Effect.Parameters["Texture"].GetValueTexture2D());
                                    //m_unifiedShader.colorMapEnabled.SetValue(true);
                                    //RenderMaterial mat = new RenderMaterial();
                                    //mat.Texture = part.Effect.Parameters["Texture"].GetValueTexture2D();
                                    //m_unifiedShader.SetParameters(mat);
                                    if (part.Effect is BasicEffect)
                                    {
                                        //(part.Effect as BasicEffect).View = m_currentCamera.ViewMatrix;
                                        //(part.Effect as BasicEffect).World = newWorld;
                                        //(part.Effect as BasicEffect).Projection = m_currentCamera.ProjectionMatrix;
                                        m_unifiedShader.colorMapTexture.SetValue((part.Effect as BasicEffect).Texture);
                                        m_unifiedShader.colorMapEnabled.SetValue(true);
                                    }

                                    if (part.Effect is EffectMaterial)
                                    {
                                        m_unifiedShader.colorMapTexture.SetValue(part.Effect.Parameters["Texture"].GetValueTexture2D());
                                        m_unifiedShader.colorMapEnabled.SetValue(true);
                                    }

                                    //foreach (EffectPass pass in part.Effect.CurrentTechnique.Passes)
                                    //{
                                    //    pass.Apply();
                                        Core.Device.SetVertexBuffer(part.VertexBuffer);
                                        Core.Device.Indices = part.IndexBuffer;
                                        Core.Device.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                            part.VertexOffset, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount);
                                    //}
                                }
                            }
                        },
                        EnableLighting && obj.RenderMaterial.EnableLighting);
                    else
                        m_unifiedShader.Render(newWorld, null, obj.RenderDelegate, EnableLighting && obj.RenderMaterial.EnableLighting); 
#endif
                }
                else
                {
                    //effect.World = obj.WorldMatrix;
                    //effect.View = m_currentCamera.ViewMatrix;
                    //effect.Projection = m_currentCamera.ProjectionMatrix;

                    //effect.DiffuseColor = new Vector3(obj.RenderMaterial.Diffuse.X, obj.RenderMaterial.Diffuse.Y, obj.RenderMaterial.Diffuse.Z);
                    //effect.SpecularColor = new Vector3(obj.RenderMaterial.Specular.X, obj.RenderMaterial.Specular.Y, obj.RenderMaterial.Specular.Z);
                    //effect.SpecularPower = obj.RenderMaterial.SpecularPower;
                    //effect.Texture = obj.RenderMaterial.ColorMap;

                    //foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                    //{
                    //    pass.Apply();
                    //    obj.RenderDelegate();
                    //}
                    if (obj is ModelObject)
                    {
                        (obj as ModelObject).Draw(obj.WorldMatrix, EnableLighting && obj.RenderMaterial.EnableLighting, m_currentCamera);
                    }
                    else
                    {
                        m_effectDR.Parameters["World"].SetValue(world);
                        m_effectDR.Parameters["View"].SetValue(m_currentCamera.ViewMatrix);
                        m_effectDR.Parameters["Projection"].SetValue(m_currentCamera.ProjectionMatrix);

                        m_effectDR.Parameters["cameraPos"].SetValue(m_currentCamera.Position);

                        m_effectDR.Parameters["Texture"].SetValue(obj.RenderMaterial.Texture);
                        m_effectDR.Parameters["NormalMap"].SetValue(obj.RenderMaterial.NormalMap);
                        m_effectDR.Parameters["HeightMap"].SetValue(obj.RenderMaterial.HeightMap);

                        m_effectDR.Parameters["SpecularMap"].SetValue(obj.RenderMaterial.SpecularMap);


                        m_effectDR.Parameters["scaleBias"].SetValue(new Vector2(0.04f, -0.03f));

                        m_effectDR.Parameters["diffuseColor"].SetValue(obj.RenderMaterial.Diffuse);

                        m_effectDR.Parameters["textureSet"].SetValue((obj.RenderMaterial.Texture != null));

                        //if (obj.Type == "SphereObject")
                        //{
                        //    m_effectDR.Parameters["bShatter"].SetValue(true);
                        //    m_effectDR.Parameters["time"].SetValue(0.1f*m_shatterTime);
                        //    Random random = new Random();
                        //    m_effectDR.Parameters["rotationalVelocity"].SetValue(new Vector3((float)random.NextDouble() * 2f - 1f, (float)random.NextDouble() * 2f - 1f, (float)random.NextDouble() * 2f - 1f));
                        //}
                        //else
                            m_effectDR.Parameters["bShatter"].SetValue(false);

                        foreach (EffectPass pass in m_effectDR.CurrentTechnique.Passes)
                        {
                            pass.Apply();


                            obj.RenderDelegate();

                        }
                    }
                    // ----------------------------------------------------------------------------------------

                    //m_game.GraphicsDevice.SetRenderTarget(colorRT);

                    //m_game.GraphicsDevice.BlendState = BlendState.AlphaBlend;

                    //Effect glow = m_game.Content.Load<Effect>("Glow");

                    //glow.Parameters["World"].SetValue(obj.WorldMatrix);
                    //glow.Parameters["WorldInverseTranspose"].SetValue(Matrix.Transpose(Matrix.Invert(obj.WorldMatrix)));
                    //glow.Parameters["WorldViewProjection"].SetValue(obj.WorldMatrix * m_currentCamera.ViewMatrix * m_currentCamera.ProjectionMatrix);
                    //glow.Parameters["ViewInverse"].SetValue(Matrix.Invert(m_currentCamera.ViewMatrix));

                    //foreach (EffectPass pass in glow.CurrentTechnique.Passes)
                    //{
                    //    pass.Apply();
                    //    obj.RenderDelegate();
                    //}
                }
#if tz
                if (RenderBoundingBoxes)
                {
                    obj.RenderBoundingBox();

                    BoundingBox box = obj.m_grabberBoundingBox;
                    Vector3[] corners = box.GetCorners();
                    Matrix tmp = obj.WorldMatrix;
                    for (int i = 0; i < corners.Length; i++)
                        Vector3.Transform(ref corners[i], ref tmp, out corners[i]);

                    DebugShapeRenderer.AddBoundingBox(corners, Color.Yellow, 0);
                }
#endif


                #region Render Wireframe

                if (m_bRenderWireframes || obj.ShowWireframe)
                {
                    // THIS IS IMPORTANT:
                    // Adapt the graphical mesh to the collision mesh using the intial offset
                    Matrix newWorld = Matrix.CreateTranslation(-obj.m_graphicsPhysOffset) * world;//obj.WorldMatrix;
                    m_wireframeRenderer.DrawWireframe(obj.RenderDelegate, newWorld, m_currentCamera.ViewMatrix, m_currentCamera.ProjectionMatrix);
                }

                #endregion
            }
#if tz
            m_game.GraphicsDevice.BlendState = BlendState.Opaque;
#endif
        }

        /// <summary>
        /// Sets the G-buffer of the deferred renderer.
        /// </summary>
        private void SetGBuffer()
        {
            m_game.GraphicsDevice.SetRenderTargets(colorRT, normalRT, depthRT);
        }

        /// <summary>
        /// Sets the backbuffer as current render target.
        /// </summary>
        private void ResolveGBuffer()
        {
            m_game.GraphicsDevice.SetRenderTargets(null);
        }

        /// <summary>
        /// Clears the G-buffer
        /// </summary>
        private void ClearGBuffer()
        {
            clearBufferEffect.Parameters["color"].SetValue(m_BackgroundColor.ToVector4());
            clearBufferEffect.Techniques[0].Passes[0].Apply();
            quadRenderer.Render(Vector2.One * -1, Vector2.One);
        }

        /// <summary>
        /// Renders a directional light for the deferred renderer.
        /// </summary>
        private void DrawDirectionalLight(Vector3 lightDirection, Color color)
        {
            directionalLightEffect.Parameters["colorMap"].SetValue(colorRT);
            directionalLightEffect.Parameters["normalMap"].SetValue(normalRT);
            directionalLightEffect.Parameters["depthMap"].SetValue(depthRT);

            directionalLightEffect.Parameters["lightDirection"].SetValue(lightDirection);
            directionalLightEffect.Parameters["Color"].SetValue(color.ToVector3());

            directionalLightEffect.Parameters["cameraPosition"].SetValue(m_currentCamera.Position);
            directionalLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(m_currentCamera.ViewMatrix * m_currentCamera.ProjectionMatrix));

            directionalLightEffect.Parameters["halfPixel"].SetValue(halfPixel);

            directionalLightEffect.Techniques[0].Passes[0].Apply();
            quadRenderer.Render(Vector2.One * -1, Vector2.One);
        }

        /// <summary>
        /// Renders a point light for the deferred renderer.
        /// </summary>
        private void DrawPointLight(Vector3 lightPosition, Color color, float lightRadius, float lightIntensity)
        {
            //set the G-Buffer parameters
            pointLightEffect.Parameters["colorMap"].SetValue(colorRT);
            pointLightEffect.Parameters["normalMap"].SetValue(normalRT);
            pointLightEffect.Parameters["depthMap"].SetValue(depthRT);

            //compute the light world matrix
            //scale according to light radius, and translate it to light position
            Matrix sphereWorldMatrix = Matrix.CreateScale(lightRadius) * Matrix.CreateTranslation(lightPosition);
            pointLightEffect.Parameters["World"].SetValue(sphereWorldMatrix);
            pointLightEffect.Parameters["View"].SetValue(m_currentCamera.ViewMatrix);
            pointLightEffect.Parameters["Projection"].SetValue(m_currentCamera.ProjectionMatrix);

            pointLightEffect.Parameters["inverseView"].SetValue(Matrix.Invert(m_currentCamera.ViewMatrix));

            //light position
            pointLightEffect.Parameters["lightPosition"].SetValue(lightPosition);

            //set the color, radius and Intensity
            pointLightEffect.Parameters["Color"].SetValue(color.ToVector3());
            pointLightEffect.Parameters["lightRadius"].SetValue(lightRadius);
            pointLightEffect.Parameters["lightIntensity"].SetValue(lightIntensity);

            //parameters for specular computations
            pointLightEffect.Parameters["cameraPosition"].SetValue(m_currentCamera.Position);
            pointLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(m_currentCamera.ViewMatrix * m_currentCamera.ProjectionMatrix));
            //size of a halfpixel, for texture coordinates alignment
            pointLightEffect.Parameters["halfPixel"].SetValue(halfPixel);
            //calculate the distance between the camera and light center
            float cameraToCenter = Vector3.Distance(m_currentCamera.Position, lightPosition);
            //if we are inside the light volume, draw the sphere's inside face
            if (cameraToCenter < lightRadius)
                m_game.GraphicsDevice.RasterizerState = RasterizerState.CullClockwise;
            else
                m_game.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;

            m_game.GraphicsDevice.DepthStencilState = DepthStencilState.None;

            pointLightEffect.Techniques[0].Passes[0].Apply();
            foreach (ModelMesh mesh in sphereModel.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    m_game.GraphicsDevice.Indices = meshPart.IndexBuffer;
                    m_game.GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);

                    m_game.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
                }
            }

            m_game.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            m_game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
        }

        /// <summary>
        /// Renders a spot light for the deferred renderer.
        /// </summary>
        private void DrawSpotLight(Vector3 lightPosition, Vector4 color, Vector3 direction, float intensity)
        {
            //set the G-Buffer parameters
            spotLightEffect.Parameters["colorMap"].SetValue(colorRT);
            spotLightEffect.Parameters["normalMap"].SetValue(normalRT);
            spotLightEffect.Parameters["depthMap"].SetValue(depthRT);

            spotLightEffect.Parameters["View"].SetValue(m_currentCamera.ViewMatrix);
            spotLightEffect.Parameters["inverseView"].SetValue(Matrix.Invert(m_currentCamera.ViewMatrix));
            spotLightEffect.Parameters["Projection"].SetValue(m_currentCamera.ProjectionMatrix);
            spotLightEffect.Parameters["InverseViewProjection"].SetValue(Matrix.Invert(m_currentCamera.ViewMatrix * m_currentCamera.ProjectionMatrix));
            spotLightEffect.Parameters["CameraPosition"].SetValue(m_currentCamera.Position);
            spotLightEffect.Parameters["GBufferTextureSize"].SetValue(lightRT.Width);

            //Set Spot Lights Geometry Buffers 
            Core.Device.SetVertexBuffer(coneModel.Meshes[0].MeshParts[0].VertexBuffer, coneModel.Meshes[0].MeshParts[0].VertexOffset);
            Core.Device.Indices = coneModel.Meshes[0].MeshParts[0].IndexBuffer;

            // Calculate the rotation
            Vector3 cn = new Vector3(0, 1, 0);
            Vector3 c0;

            direction.Normalize();

            if (lightPosition.Y >= (lightPosition + direction * Vector3.One).Y)
                c0 = -direction;
            else
                c0 = direction;

            cn.Normalize();

            Vector3 r;
            r = Vector3.Cross(cn, c0);

            r.Normalize();

            float theta = 0.0f;

            Quaternion rotation = Quaternion.Identity;

            if (cn != c0)
            {
                theta = (float)Math.Cos(Vector3.Dot(c0, cn));

                rotation = Quaternion.CreateFromAxisAngle(r, theta);
            }
            
            //Set Spot Light Parameters 
            spotLightEffect.Parameters["World"].SetValue(Matrix.CreateScale(intensity) * Matrix.CreateFromQuaternion(rotation) * Matrix.CreateTranslation(lightPosition));
            spotLightEffect.Parameters["LightViewProjection"].SetValue(m_currentCamera.ViewMatrix * m_currentCamera.ProjectionMatrix);
            spotLightEffect.Parameters["LightPosition"].SetValue(lightPosition); 
            spotLightEffect.Parameters["LightColor"].SetValue(color);
            spotLightEffect.Parameters["LightIntensity"].SetValue(intensity);
            spotLightEffect.Parameters["S"].SetValue(direction);
            spotLightEffect.Parameters["LightAngleCos"].SetValue(2f);
            spotLightEffect.Parameters["LightHeight"].SetValue(m_currentCamera.ZFarPlane);
            spotLightEffect.Parameters["Shadows"].SetValue(false);
            spotLightEffect.Parameters["shadowMapSize"].SetValue(1024);
            spotLightEffect.Parameters["DepthPrecision"].SetValue(m_currentCamera.ZFarPlane);
            spotLightEffect.Parameters["DepthBias"].SetValue(1f/2000f);

            //Apply 
            spotLightEffect.CurrentTechnique.Passes[0].Apply();
            
            //Draw 
            Core.Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, coneModel.Meshes[0].MeshParts[0].NumVertices, 
                                                    coneModel.Meshes[0].MeshParts[0].StartIndex,
                                                    coneModel.Meshes[0].MeshParts[0].PrimitiveCount);
        }

        /// <summary>
        /// Renders all lights for the deferred renderer.
        /// </summary>
        private void DrawLights(GameTime gameTime)
        {
            m_game.GraphicsDevice.SetRenderTarget(lightRT);
            m_game.GraphicsDevice.Clear(Color.Transparent);
            m_game.GraphicsDevice.BlendState = BlendState.AlphaBlend;
            m_game.GraphicsDevice.DepthStencilState = DepthStencilState.None;


            foreach (LightObject light in m_sceneLightsList)
            {
                if (light.Source.Type == LightType.Directional && light.Source.Enabled)
                    DrawDirectionalLight(light.Source.Direction, new Color(light.Source.Diffuse.X, light.Source.Diffuse.Y, light.Source.Diffuse.Z));

                if (light.Source.Type == LightType.SpotLight && light.Source.Enabled)
                    DrawSpotLight(light.Position, light.Source.Diffuse, light.Source.Direction, light.Source.Range);

                if (light.Source.Type == LightType.Point && light.Source.Enabled)
                    DrawPointLight(light.Source.Position, new Color((int)(light.Source.Diffuse.X*255f), (int)(light.Source.Diffuse.Y*255f), (int)(light.Source.Diffuse.Z*255f)), light.Source.Range, light.Source.Attenuation0);
            }

            Color[] colors = new Color[10];
            colors[0] = Color.Red; colors[1] = Color.Blue;
            colors[2] = Color.IndianRed; colors[3] = Color.CornflowerBlue;
            colors[4] = Color.Gold; colors[5] = Color.Green;
            colors[6] = Color.Crimson; colors[7] = Color.SkyBlue;
            colors[8] = Color.Red; colors[9] = Color.ForestGreen;
            float angle = (float)gameTime.TotalGameTime.TotalSeconds;
            int n = 0;

            for (int i = 0; i < n; i++)
            {
                Vector3 pos = new Vector3((float)Math.Sin(i * MathHelper.TwoPi / n + angle), 0.30f, (float)Math.Cos(i * MathHelper.TwoPi / n + angle));
                DrawPointLight(pos * 40, colors[i % 10], 5, 2);
                pos = new Vector3((float)Math.Cos((i + 5) * MathHelper.TwoPi / n - angle), 0.30f, (float)Math.Sin((i + 5) * MathHelper.TwoPi / n - angle));
                DrawPointLight(pos * 20, colors[i % 10], 10, 1);
                pos = new Vector3((float)Math.Cos(i * MathHelper.TwoPi / n + angle), 0.10f, (float)Math.Sin(i * MathHelper.TwoPi / n + angle));
                DrawPointLight(pos * 75, colors[i % 10], 15, 2);
                pos = new Vector3((float)Math.Cos(i * MathHelper.TwoPi / n + angle), -0.3f, (float)Math.Sin(i * MathHelper.TwoPi / n + angle));
                DrawPointLight(pos * 20, colors[i % 10], 10, 2);
            }

            //DrawPointLight(new Vector3(0, (float)Math.Sin(angle * 0.8) * 40, 0), Color.Red, 10, 5);
            //DrawPointLight(new Vector3(0, 25, 0), Color.White, 10, 1);
            //DrawPointLight(new Vector3(0, 5, 70), Color.Wheat, 5 + 10 * (float)Math.Sin(5 * angle), 3);

            //DrawDirectionalLight(new Vector3(1, -1, -1), Color.White);


            m_game.GraphicsDevice.BlendState = BlendState.Opaque;
            m_game.GraphicsDevice.DepthStencilState = DepthStencilState.None;
            m_game.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;

            //if(m_bSSAO)
            //    m_game.GraphicsDevice.SetRenderTarget(m_ssaoRT);//null);
            //else
            //    m_game.GraphicsDevice.SetRenderTarget(null);
            
            //Combine everything
            finalCombineEffect.Parameters["colorMap"].SetValue(colorRT);
            finalCombineEffect.Parameters["lightMap"].SetValue(lightRT);
            finalCombineEffect.Parameters["halfPixel"].SetValue(halfPixel);

            finalCombineEffect.Techniques[0].Passes[0].Apply();
            quadRenderer.Render(Vector2.One * -1, Vector2.One);

            // Output FPS and 'credits'
            double fps = (1000 / gameTime.ElapsedGameTime.TotalMilliseconds);
            fps = Math.Round(fps, 0);        
        }

        /// <summary>
        /// Creates a video capture device for the marker tracking.
        /// </summary>
        private void AddVideoCaptureDevice(IVideoCapture device)
        {
            if (device == null)
                return;

            if (!device.Initialized)
                ExceptionManager.Add(new Exception("You should initialize the video capture device first " +
                    "before you add it"));

            m_videoCaptureDevice = device;            

            SetVideoID();
            SetTrackerVideoID();

            m_bMarkerTrackingInitialized = true;
        }

        /// <summary>
        /// Updates the optical marker tracker as well as the video image
        /// </summary>
        protected void UpdateTracker()
        {
            while (true)
            {
                // Synchronize the frame update with tracker update
                while (m_lTrackerUpdateCount > m_lFrameUpdateCount)
                {
                    Thread.Sleep(10);
                }

                UpdateTrackerAndImage();

                m_lTrackerUpdateCount++;                
            }
        }

        /// <summary>
        /// Updates the optical marker tracker as well as the video image
        /// </summary>
        protected void UpdateTrackerAndImage()
        {
            if (m_bFreezeVideo)
                return;

            // Wait for video ID to change before updating the tracker and image
            while (m_bWaitForVideoIDChange) { }

            m_bWaitForTrackerUpdate = true;

            // If a static image is used and the image is already processed, then we don't
            // need to process it again
            if (!(m_videoCaptureDevice is NullCapture))
            {
                bool processSeparateImagePtr = false;
                bool passToMarkerTracker = false;

                if (m_bShowCameraImage)
                {
                    //processLeftImageData = true;

                    if (m_markerTracker != null)
                    {
                        passToMarkerTracker = true;
                       
                    }
                    else
                    {
                        // TODO
                    }
                }

                //Kinect.TextureColor.GetData<int>(m_iBufferedVideoImage);
                //System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(640, 480, 4, System.Drawing.Imaging.PixelFormat.Format32bppArgb, (IntPtr)m_iBufferedVideoImage[0]);
                //m_videoCaptureDevice.GetImageTexture(m_iBufferedVideoImage, ref m_pBufferedVideoPtr, bmp);
                System.Drawing.Bitmap bmp = null;

                if (m_videoCaptureDevice is KinectCapture)
                    ((KinectCapture)m_videoCaptureDevice).Image = Kinect.TextureColor;

                m_videoCaptureDevice.GetImageTexture(m_iBufferedVideoImage, ref m_pBufferedVideoPtr, bmp);
                

                SetTextureData(0);

                if (processSeparateImagePtr)
                    m_videoCaptureDevice.GetImageTexture(null, ref m_pBufferedVideoPtr, bmp);

                if (passToMarkerTracker)
                    m_markerTracker.ProcessImage(m_videoCaptureDevice, m_pBufferedVideoPtr);

                if (m_videoCaptureDevice is NullCapture)
                    ((NullCapture)m_videoCaptureDevice).IsImageAlreadyProcessed = true;               
            }

            float elapsedTime = 0;
            float curTime = (float)DateTime.Now.TimeOfDay.TotalMilliseconds;

            if (m_fPrevTrackerTime != 0)
                elapsedTime = curTime - m_fPrevTrackerTime;

            m_fPrevTrackerTime = curTime;

            try
            {
                foreach (ARMarkerController marker in m_sceneMarkerControllersList)
                    marker.Update(elapsedTime);
            }
            catch (Exception) { }

            m_bWaitForTrackerUpdate = false;
        }

        /// <summary>
        /// Sets the video texture data.
        /// </summary>
        /// <param name="id"></param>
        protected void SetTextureData(int id)
        {
            if (m_VideoTexture.IsDisposed)
                m_VideoTexture = new Texture2D(Core.Device, m_VideoTexture.Width, m_VideoTexture.Height, false, SurfaceFormat.Color);

            while (m_bRenderingVideoTexture) { }

            m_bCopyingVideoImage = true;

            try
            {
                m_VideoTexture.SetData<int>(m_iBufferedVideoImage);
            }
            catch (Exception exp)
            {
                Core.Device.Textures[0] = null;
                //m_VideoTexture.SetData<int>(m_iBufferedVideoImage);
            }

            m_bCopyingVideoImage = false;
        }

        /// <summary>
        /// Initializes the sizes of the buffered video image holders. 
        /// </summary>
        /// <param name="id">Either 0 (left eye) or 1 (right eye). Should be 0 if mono.</param>
        /// <param name="videoDevice"></param>
        protected virtual void InitializeVideoImageSize()
        {
            int imageSize = m_videoCaptureDevice.Width * m_videoCaptureDevice.Height;
            if ((m_pBufferedVideoPtr == null) || (imageSize != m_iBufferedVideoImage.Length))
            {
                m_iBufferedVideoImage = new int[imageSize];

                m_VideoTexture = new Texture2D(Core.Device, m_videoCaptureDevice.Width, m_videoCaptureDevice.Height, false, SurfaceFormat.Color);
            }
        }

        /// <summary>
        /// Initilizes the sizes of the bufferd video image pointers.
        /// </summary>
        /// <param name="videoDevice"></param>
        protected virtual void InitializeVideoPointerSize(IVideoCapture videoDevice)
        {
            int imageSize = videoDevice.Width * videoDevice.Height;
            // if IResizer is set, then we'll use the size of the resized image
            // Note that the ScalingFactor is multiplied twice; one for width, and the other for height
            if (videoDevice.MarkerTrackingImageResizer != null)
                imageSize = (int)(imageSize * videoDevice.MarkerTrackingImageResizer.ScalingFactor *
                    videoDevice.MarkerTrackingImageResizer.ScalingFactor);

            if (!videoDevice.GrayScale)
            {
                switch (videoDevice.Format)
                {
                    case ImageFormat.GRAYSCALE_8: break; // Nothing to do 
                    case ImageFormat.R5G6B5_16: imageSize *= 2; break;
                    case ImageFormat.B8G8R8_24:
                    case ImageFormat.R8G8B8_24: imageSize *= 3; break;
                    case ImageFormat.R8G8B8A8_32:
                    case ImageFormat.B8G8R8A8_32:
                    case ImageFormat.A8B8G8R8_32: imageSize *= 4; break;
                }
            }

#if WINDOWS
            if (m_iPrevPointerSize == 0)
            {
                m_pBufferedVideoPtr = Marshal.AllocHGlobal(imageSize);
            }
            else if (m_iPrevPointerSize != imageSize)
            {
                Marshal.FreeHGlobal(m_pBufferedVideoPtr);
                m_pBufferedVideoPtr = Marshal.AllocHGlobal(imageSize);
            }
#endif

            m_iPrevPointerSize = imageSize;
        }

        /// <summary>
        /// Sets the video capture device ID used to perform marker tracking (if available).
        /// This ID should correspond to the videoDeviceID given to the initialized video device
        /// using InitVideoCapture method. 
        /// </summary>
        private void SetTrackerVideoID()
        {
            // Wait for the tracker update to end before modifying the ID
            while (m_bWaitForTrackerUpdate) { }
            
            m_bWaitForVideoIDChange = true;

            InitializeVideoPointerSize(m_videoCaptureDevice);

            m_bWaitForVideoIDChange = false;
        }

        /// <summary>
        /// Sets the video ID for left eye to use for stereo augmented reality. If you use 
        /// single camera for stereo, then you should set both LeftEyeVideoID and RightEyeVideoID to 
        /// the same video ID. 
        /// </summary>
        private void SetVideoID()
        {            
            //if (!cameraNode.Stereo)
            //    throw new GoblinException("You should set OverlayVideoID instead since your current " +
            //        "camera node does not contain stereo information");

            // Wait for the tracker update to end before modifying the ID
            while (m_bWaitForTrackerUpdate) { }
            m_bWaitForVideoIDChange = true;

            InitializeVideoImageSize();
            
            m_bWaitForVideoIDChange = false;
        }
        
        #endregion

        #region Other Overrides

        /// <summary>
        /// Dispose the scene.
        /// </summary>
        public /*override*/ void Dispose()
        {
            //base.Dispose(disposing);

            m_bIsDisposed = true;

            foreach (SceneObject obj in m_sceneObjectsList)
                obj.Dispose();

            foreach (SoundObject sound in m_sceneSoundsList)
                sound.Dispose();

            //m_uiRenderer.Dispose();

            if (bRunningSpeechRecognition)
            {
                bRunningSpeechRecognition = false;
                this.Kinect.Sensor.AudioSource.Stop();
                sre.RecognizeAsyncCancel();
                sre.RecognizeAsyncStop();
            }

            m_unifiedShader.Dispose();

            if (m_markerTrackingThread != null)
                m_markerTrackingThread.Abort();

            if (iTracker != null)
                iTracker.Dispose();

            m_sceneCamerasList.Clear();
            m_sceneControllersList.Clear();
            m_sceneLightsList.Clear();
            m_sceneMarkerControllersList.Clear();
            m_sceneObjectsList.Clear();
            m_sceneParticleList.Clear();
            m_sceneText3D.Clear();
            m_scenePhysicsList.Clear();

            if (m_videoCaptureDevice != null)
                m_videoCaptureDevice.Dispose();

            if (m_markerTracker != null)
                m_markerTracker.Dispose();

            m_collisionMeshRenderer.Clear();
            m_constraintsRenderer.Clear();

            // Reset the debug info
            Core.ShowFPS = false;
            Core.ShowTriangleCount = false;
            Core.ShowNotifications = false;
            Core.ShowCameraPosition = false;

            if (this.m_kinect != null && this.m_bKinectEnabled)
            {
                this.m_kinect.Dispose();
            }

            if (m_pBufferedVideoPtr != IntPtr.Zero)
            {
                try
                {
                    Marshal.FreeHGlobal(m_pBufferedVideoPtr);
                }
                catch (Exception) { }
            }
        }

        /// <summary>
        /// Loads the content, which is needed for the scene.
        /// </summary>
        public /*protected override*/ void LoadContent()
        {
            halfPixel = new Vector2()
            {
                X = 0.5f / (float)m_game.GraphicsDevice.PresentationParameters.BackBufferWidth,
                Y = 0.5f / (float)m_game.GraphicsDevice.PresentationParameters.BackBufferHeight
            };

            int backbufferWidth = m_game.GraphicsDevice.PresentationParameters.BackBufferWidth;
            int backbufferHeight = m_game.GraphicsDevice.PresentationParameters.BackBufferHeight;

            colorRT  = new RenderTarget2D(m_game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);
            normalRT = new RenderTarget2D(m_game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Color, DepthFormat.None);
            depthRT  = new RenderTarget2D(m_game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Single, DepthFormat.None);
            lightRT  = new RenderTarget2D(m_game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Color, DepthFormat.None);

            ////Create SSAO 
            //m_ssao = new SSAO(m_game, m_graphics.PreferredBackBufferWidth, m_graphics.PreferredBackBufferHeight);

            //Create Scene Render Target 
            //m_ssaoRT = new RenderTarget2D(m_game.GraphicsDevice, m_graphics.PreferredBackBufferWidth,
            //       m_graphics.PreferredBackBufferHeight, false,
            //       SurfaceFormat.Color, DepthFormat.Depth24Stencil8); 
            
            //scene.InitializeScene();
            //models = new Model[4];
            //models[3] = m_game.Content.Load<Model>("Models\\ship1");
            //models[1] = m_game.Content.Load<Model>("Models\\ship2");
            //models[2] = m_game.Content.Load<Model>("Models\\lizard");
            //models[0] = m_game.Content.Load<Model>("Models\\ground");

            clearBufferEffect = Core.EmbeddedContent.Load<Effect>("ClearGBuffer");
            directionalLightEffect = Core.EmbeddedContent.Load<Effect>("DirectionalLight");
            finalCombineEffect = Core.EmbeddedContent.Load<Effect>("CombineFinal");
            pointLightEffect = Core.EmbeddedContent.Load<Effect>("PointLight");
            spotLightEffect = Core.EmbeddedContent.Load<Effect>("SpotLight");
            m_effectDR = Core.RenderGBuffer;
            sphereModel = Core.EmbeddedContent.Load<Model>("sphere");
            coneModel = Core.EmbeddedContent.Load<Model>("cone");

            m_spriteBatch = new SpriteBatch(m_game.GraphicsDevice);
            m_font = Core.EmbeddedContent.Load<SpriteFont>("DebugFont");

            LineDrawer = new BasicEffect(Core.Device);

            quadRenderer.LoadContent();
            //base.LoadContent();
        }

        #endregion
    }
}
